changeset 666:498325f3f086

Merging upstream changes
author nwp@mrrush.otago.ac.nz
date Wed, 17 May 2006 09:27:26 +1200
parents 964c43d64815 (current diff) fa2fa5d2b78f (diff)
children d7c11207bbb7
files MoinMoin/_tests/broken/test_converter_text_html_text_x_moin.py MoinMoin/_tests/broken/test_parser_wiki.py MoinMoin/converter/text_html_text_x_moin.py MoinMoin/formatter/base.py MoinMoin/formatter/xml_docbook.py MoinMoin/parser/CSV.py MoinMoin/parser/cplusplus.py MoinMoin/parser/docbook.py MoinMoin/parser/irc.py MoinMoin/parser/java.py MoinMoin/parser/pascal.py MoinMoin/parser/plain.py MoinMoin/parser/python.py MoinMoin/parser/rst.py MoinMoin/parser/wiki.py MoinMoin/parser/xslt.py MoinMoin/request/MODPYTHON.py
diffstat 65 files changed, 7050 insertions(+), 6370 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Tue May 16 11:44:24 2006 +1200
+++ b/.hgignore	Wed May 17 09:27:26 2006 +1200
@@ -1,4 +1,5 @@
 \{arch\}
 .*\.arch-ids/.*
 .*\.py[co]
+sa
 
--- a/MoinMoin/Page.py	Tue May 16 11:44:24 2006 +1200
+++ b/MoinMoin/Page.py	Wed May 17 09:27:26 2006 +1200
@@ -1007,14 +1007,16 @@
             from MoinMoin.formatter.text_html import Formatter
             self.formatter = Formatter(request, store_pagelinks=1)
         elif not self.formatter:
-            formatterName = self.output_mimetype.replace('/', '_').replace('.', '_') # XXX use existing fn for that
-            try:
-                Formatter = wikiutil.importPlugin(request.cfg, "formatter", formatterName, "Formatter")
-                self.formatter = Formatter(request)
-            except wikiutil.PluginMissingError:
-                from MoinMoin.formatter.text_html import Formatter
-                self.formatter = Formatter(request, store_pagelinks=1)
-                self.output_mimetype = "text/html"
+            omt = wikiutil.MimeType(self.output_mimetype)
+            for module_name in omt.module_name():
+                try:
+                    Formatter = wikiutil.importPlugin(request.cfg, "formatter", module_name, "Formatter")
+                    self.formatter = Formatter(request)
+                    break
+                except wikiutil.PluginMissingError:
+                    pass
+            else:
+                raise "Plugin missing error!" # XXX what now?
         request.formatter = self.formatter
         self.formatter.setPage(self)
         if self.hilite_re:
@@ -1221,15 +1223,17 @@
                     ) % {'pagename': self.formatter.text(self.page_name)})
                     request.write(''.join(pi_formtext))
 
-        # Load the parser, or default to plain text parser that will
-        # just show the page raw source.
-        # TODO: do we need this magic? any effect on debugging?
-        try:
-            Parser = wikiutil.importPlugin(self.request.cfg, "parser", 
-                                           self.pi_format, "Parser")
-        except wikiutil.PluginMissingError:
-            from MoinMoin.parser.plain import Parser
-
+        # Load the parser
+        mt = wikiutil.MimeType(self.pi_format)
+        for module_name in mt.module_name():
+            try:
+                Parser = wikiutil.importPlugin(self.request.cfg, "parser", module_name, "Parser")
+                break
+            except wikiutil.PluginMissingError:
+                pass
+        else:
+            raise "No matching parser" # XXX what do we use if nothing at all matches?
+            
         # start wiki content div
         request.write(self.formatter.startContent(content_id))
 
@@ -1312,11 +1316,15 @@
             self.getFormatterName() in self.cfg.caching_formats):
             # Everything is fine, now check the parser:
             if parser is None:
-                try:
-                    parser = wikiutil.importPlugin(self.request.cfg, "parser",
-                                                   self.pi_format, "Parser")
-                except wikiutil.PluginMissingError:
-                    pass
+                mt = wikiutil.MimeType(self.pi_format)
+                for module_name in mt.module_name():
+                    try:
+                        parser = wikiutil.importPlugin(self.request.cfg, "parser", module_name, "Parser")
+                        break
+                    except wikiutil.PluginMissingError:
+                        pass
+                else:
+                    raise "no matching parser" # XXX what now?
             return getattr(parser, 'caching', False)
         return False
 
--- a/MoinMoin/PageGraphicalEditor.py	Tue May 16 11:44:24 2006 +1200
+++ b/MoinMoin/PageGraphicalEditor.py	Wed May 17 09:27:26 2006 +1200
@@ -17,7 +17,7 @@
 from MoinMoin.util import filesys
 import MoinMoin.util.web
 import MoinMoin.util.mail
-from MoinMoin.parser.wiki import Parser
+from MoinMoin.parser.text_moin_wiki import Parser
 
 from StringIO import StringIO
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/_tests/broken/test_converter_text_html_text_moin_wiki.py	Wed May 17 09:27:26 2006 +1200
@@ -0,0 +1,1140 @@
+# -*- coding: utf-8 -*-
+"""
+MoinMoin - MoinMoin.text_html_text_moin_wiki Tests
+
+@copyright: 2005 by Bastian Blank, ThomasWaldmann
+@license: GNU GPL, see COPYING for details.
+"""
+
+import unittest
+from MoinMoin import _tests
+
+from cStringIO import StringIO
+from MoinMoin.converter import text_html_text_moin_wiki as converter
+from MoinMoin.parser.wiki import Parser
+from MoinMoin.formatter.text_gedit import Formatter
+from MoinMoin.request import Clock
+
+convert = converter.convert
+error = converter.ConvertError
+
+
+class BaseTests(unittest.TestCase):
+
+    def setUp(self):
+        self.cfg = _tests.TestConfig(self.request, bang_meta=True)
+        
+    def tearDown(self):
+        del self.cfg
+
+    def do_convert_real(self, func_args, successful=True):
+        try:
+            ret = convert(*func_args)
+        except error, e:
+            if successful:
+                self.fail("fails with parse error: %s" % e)
+            else:
+                return
+        if successful:
+            return ret
+        else:
+            self.fail("doesn't fail with parse error")
+
+
+class MinimalPage(object):
+    def __init__(self):
+        self.hilite_re = None
+        self.page_name = "testpage"
+
+
+class MinimalRequest(object):
+    # TODO: do we really need this class? no other test uses a request replacement.
+
+    def __init__(self, request):
+        self.request = request
+        self.clock = Clock()
+        
+        # This is broken - tests that need correct content_lang will fail
+        self.content_lang = None
+        self.current_lang = None
+        
+        self.form = {}
+        self._page_headings = {}
+        self.result = []
+
+    def getText(self, text, formatted=True):
+        return text
+
+    def write(self, text):
+        self.result.append(text)
+
+    def __getattr__(self, name):
+        return getattr(self.request, name)
+
+
+class ConvertBlockRepeatableTests(BaseTests):
+    def do(self, text, output):
+        text = text.lstrip('\n')
+        output = output.strip('\n')
+        request = MinimalRequest(self.request)
+        page = MinimalPage()
+        formatter = Formatter(request)
+        formatter.setPage(page)
+        Parser(text, request).format(formatter)
+        repeat = ''.join(request.result).strip('\n')
+        self.failUnlessEqual(repeat, output)
+        out = self.do_convert_real([request, page.page_name, repeat])
+        self.failUnlessEqual(text, out)
+
+    def testComment01(self):
+        test = ur"""
+##test
+"""
+        output = u"""<pre class="comment">\n##test</pre>"""
+        self.do(test, output)
+
+    def testComment02(self):
+        test = ur"""
+##test
+##test
+"""
+        output = u"""
+<pre class="comment">\n##test</pre>
+<pre class="comment">\n##test</pre>
+"""
+        self.do(test, output)
+
+    def testHeading01(self):
+        test = ur"""
+= test1 =
+
+"""
+        output = ur"""
+<h2>test1</h2>
+"""
+        self.do(test, output)
+
+    def testHeading02(self):
+        test = ur"""
+= test1 =
+
+== test2 ==
+
+"""
+        output = ur"""
+<h2>test1</h2>
+<h3>test2</h3>
+"""
+        self.do(test, output)
+
+    def testListSuccess01(self):
+        test = ur"""
+ * test
+
+"""
+        output = ur"""
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testListSuccess02(self):
+        test = ur"""
+ 1. test
+
+"""
+        output = ur"""
+<ol type="1">
+<li><p>test </p>
+</li>
+</ol>
+"""
+        self.do(test, output)
+
+    def testListSuccess03(self):
+        test = ur"""
+ test:: test
+
+"""
+        output = ur"""
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+"""
+        self.do(test, output)
+
+    def testListSuccess04(self):
+        test = ur"""
+ * test
+ * test
+
+"""
+        output = ur"""
+<ul>
+<li><p>test </p>
+</li>
+<li><p>test </p>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testListSuccess05(self):
+        test = ur"""
+ 1. test
+ 1. test
+
+"""
+        output = ur"""
+<ol type="1">
+<li><p>test </p>
+</li>
+<li><p>test </p>
+</li>
+</ol>
+"""
+        self.do(test, output)
+
+    def testListSuccess06(self):
+        test = ur"""
+ test:: test
+ test:: test
+
+"""
+        output = ur"""
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+"""
+        self.do(test, output)
+
+    def testListSuccess07(self):
+        test = ur"""
+ * test
+  
+ * test
+
+"""
+        output = ur"""
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testListSuccess08(self):
+        test = ur"""
+ 1. test
+  
+ 1. test
+
+"""
+        output = ur"""
+<ol type="1">
+<li><p>test </p>
+</li>
+</ol>
+<ol type="1">
+<li><p>test </p>
+</li>
+</ol>
+"""
+        self.do(test, output)
+
+    def testListSuccess09(self):
+        test = ur"""
+ test:: test
+  
+ test:: test
+
+"""
+        output = ur"""
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+"""
+        self.do(test, output)
+
+    def testListSuccess10(self):
+        test = ur"""
+ * test
+  * test
+
+"""
+        output = ur"""
+<ul>
+<li><p>test </p>
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testListSuccess11(self):
+        test = ur"""
+ 1. test
+  1. test
+
+"""
+        output = ur"""
+<ol type="1">
+<li><p>test </p>
+<ol type="1">
+<li><p>test </p>
+</li>
+</ol>
+</li>
+</ol>
+"""
+        self.do(test, output)
+
+    def testListSuccess12(self):
+        test = ur"""
+ test:: test
+  test:: test
+
+"""
+        output = ur"""
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+</dd>
+</dl>
+"""
+        self.do(test, output)
+
+    def testListSuccess13(self):
+        test = ur"""
+ * test
+  * test
+ * test
+
+"""
+        output = ur"""
+<ul>
+<li><p>test </p>
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+</li>
+<li><p>test </p>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testListSuccess14(self):
+        test = ur"""
+ 1. test
+  1. test
+ 1. test
+
+"""
+        output = ur"""
+<ol type="1">
+<li><p>test </p>
+<ol type="1">
+<li><p>test </p>
+</li>
+</ol>
+</li>
+<li><p>test </p>
+</li>
+</ol>
+"""
+        self.do(test, output)
+
+    def testListSuccess15(self):
+        test = ur"""
+ test:: test
+  test:: test
+ test:: test
+
+"""
+        output = ur"""
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+</dd>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+"""
+        self.do(test, output)
+
+    def testListSuccess16(self):
+        test = ur"""
+ * test
+
+ 1. test
+
+"""
+        output = ur"""
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+<ol type="1">
+<li><p>test </p>
+</li>
+</ol>
+"""
+        self.do(test, output)
+
+    def testListSuccess17(self):
+        test = ur"""
+ * test
+
+ test:: test
+
+"""
+        output = ur"""
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+"""
+        self.do(test, output)
+
+    def testListSuccess18(self):
+        test = ur"""
+ 1. test
+
+ * test
+
+"""
+        output = ur"""
+<ol type="1">
+<li><p>test </p>
+</li>
+</ol>
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testListSuccess19(self):
+        test = ur"""
+ 1. test
+
+ test:: test
+
+"""
+        output = ur"""
+<ol type="1">
+<li><p>test </p>
+</li>
+</ol>
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+"""
+        self.do(test, output)
+
+    def testListSuccess20(self):
+        test = ur"""
+ test:: test
+
+ * test
+
+"""
+        output = ur"""
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testListSuccess21(self):
+        test = ur"""
+ test:: test
+
+ 1. test
+
+"""
+        output = ur"""
+<dl>
+<dt>test</dt>
+<dd><p>test </p>
+</dd>
+</dl>
+<ol type="1">
+<li><p>test </p>
+</li>
+</ol>
+"""
+        self.do(test, output)
+
+    def testListSuccess23(self):
+        test = ur"""
+ 1. test
+  * test
+
+"""
+        output = ur"""
+<ol type="1">
+<li><p>test </p>
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+</li>
+</ol>
+"""
+        self.do(test, output)
+
+    def testListSuccess26(self):
+        test = ur"""
+ * test
+
+test
+
+"""
+        output = ur"""
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+<p>test </p>
+"""
+        self.do(test, output)
+
+    def testListSuccess28(self):
+        test = ur"""
+ * test
+
+ test
+
+"""
+        output = ur"""
+<ul>
+<li><p>test </p>
+<p>test </p>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testListSuccess29(self):
+        test = ur"""
+ * test
+  * test
+ test
+"""
+        output = ur"""
+"""
+        self.do(test, output)
+
+    def testListSuccess30(self):
+        test = ur"""
+ * test
+  * test
+  test
+"""
+        output = ur"""
+"""
+        self.do(test, output)
+
+    def testParagraph1(self):
+        test = ur"""
+test
+
+"""
+        output = ur"""
+<p>test </p>
+"""
+        self.do(test, output)
+
+    def testParagraph2(self):
+        test = ur"""
+test
+
+test
+
+"""
+        output = ur"""
+<p>test </p>
+<p>test </p>
+"""
+        self.do(test, output)
+
+    def testPreSuccess1(self):
+        test = ur"""
+{{{
+test
+}}}
+
+"""
+        output = ur"""
+<pre>
+test
+</pre>
+"""
+        self.do(test, output)
+
+    def testPreSuccess2(self):
+        test = ur"""
+{{{
+test
+test
+}}}
+
+"""
+        output = ur"""
+<pre>
+test
+test
+</pre>
+"""
+        self.do(test, output)
+
+    def testPreSuccess3(self):
+        test = ur"""
+{{{
+test
+
+test
+}}}
+
+"""
+        output = ur"""
+<pre>
+test
+
+test
+</pre>
+"""
+        self.do(test, output)
+
+    def testPreSuccess4(self):
+        test = ur"""
+{{{
+ * test
+}}}
+
+"""
+        output = ur"""
+<pre>
+ * test
+</pre>
+"""
+        self.do(test, output)
+
+    def testPreSuccess5(self):
+        test = ur"""
+{{{
+  }}}
+
+"""
+        output = ur"""
+<pre>
+  </pre>
+"""
+        self.do(test, output)
+
+    def testPreSuccess6(self):
+        test = ur"""
+ * {{{
+test
+}}}
+
+"""
+        output = ur"""
+<ul>
+<li>
+<pre>
+test
+</pre>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testPreSuccess7(self):
+        test = ur"""
+ * {{{
+   test
+   }}}
+
+"""
+        output = ur"""
+<ul>
+<li>
+<pre>
+   test
+   </pre>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testPreSuccess8(self):
+        test = ur"""
+ * test
+ {{{
+test
+}}}
+
+"""
+        output = ur"""
+<ul>
+<li><p>test 
+</p>
+<pre>
+test
+</pre>
+</li>
+</ul>
+"""
+        self.do(test, output)
+
+    def testPreSuccess9(self):
+        test = ur"""
+ * test
+
+{{{
+test
+}}}
+
+"""
+        output = ur"""
+<ul>
+<li><p>test </p>
+</li>
+</ul>
+
+<pre>
+test
+</pre>
+"""
+        self.do(test, output)
+
+    def testRule1(self):
+        test = ur"""
+----
+
+"""
+        output = ur"""
+<hr/>
+"""
+        self.do(test, output)
+
+    def testTable01(self):
+        test = ur"""
+|| ||
+
+"""
+        output = ur"""
+<div>
+<table>
+<tr>
+<td>
+<p> </p>
+</td>
+</tr>
+</table>
+</div>
+"""
+        self.do(test, output)
+
+    def testTable02(self):
+        test = ur"""
+||test||
+
+"""
+        output = ur"""
+<div>
+<table>
+<tr>
+<td>
+<p>test</p>
+</td>
+</tr>
+</table>
+</div>
+"""
+        self.do(test, output)
+
+    def testTable03(self):
+        test = ur"""
+||test||test||
+
+"""
+        output = ur"""
+<div>
+<table>
+<tr>
+<td>
+<p>test</p>
+</td>
+<td>
+<p>test</p>
+</td>
+</tr>
+</table>
+</div>
+"""
+        self.do(test, output)
+
+    def testTable04(self):
+        test = ur"""
+||test||
+||test||test||
+
+"""
+        output = ur"""
+<div>
+<table>
+<tr>
+<td>
+<p>test</p>
+</td>
+</tr>
+<tr>
+<td>
+<p>test</p>
+</td>
+<td>
+<p>test</p>
+</td>
+</tr>
+</table>
+</div>
+"""
+        self.do(test, output)
+
+    def testTable05(self):
+        test = ur"""
+||||test||
+||test||test||
+
+"""
+        output = ur"""
+<div>
+<table>
+<tr>
+<td colspan="2" style="text-align: center;">
+<p>test</p>
+</td>
+</tr>
+<tr>
+<td>
+<p>test</p>
+</td>
+<td>
+<p>test</p>
+</td>
+</tr>
+</table>
+</div>
+"""
+        self.do(test, output)
+
+    def testTable06(self):
+        test = ur"""
+||||test||test||
+||test||||test||
+
+"""
+        output = ur"""
+<div>
+<table>
+<tr>
+<td colspan="2" style="text-align: center;">
+<p>test</p>
+</td>
+<td>
+<p>test</p>
+</td>
+</tr>
+<tr>
+<td>
+<p>test</p>
+</td>
+<td colspan="2" style="text-align: center;">
+<p>test</p>
+</td>
+</tr>
+</table>
+</div>
+"""
+        self.do(test, output)
+
+class ConvertInlineFormatRepeatableTests(BaseTests):
+    def do(self, text, output):
+        text = text.lstrip('\n')
+        output = output.strip('\n')
+        output = "<p>%s </p>" % output
+        request = MinimalRequest(self.request)
+        page = MinimalPage()
+        formatter = Formatter(request)
+        formatter.setPage(page)
+        Parser(text, request).format(formatter)
+        repeat = ''.join(request.result).strip('\n')
+        self.failUnlessEqual(repeat, output)
+        out = self.do_convert_real([request, page.page_name, repeat])
+        out = out.rstrip('\n')
+        self.failUnlessEqual(text, out)
+
+    def testEmphasis01(self):
+        test = ur"''test''"
+        output = ur"<em>test</em>"
+        self.do(test, output)
+
+    def testEmphasis02(self):
+        test = ur"'''test'''"
+        output = ur"<strong>test</strong>"
+        self.do(test, output)
+
+    def testEmphasis03(self):
+        test = ur"'''''test'''''"
+        output = ur"<em><strong>test</strong></em>"
+        self.do(test, output)
+
+    def testEmphasis04(self):
+        test = ur"''test'''test'''''"
+        output = ur"<em>test<strong>test</strong></em>"
+        self.do(test, output)
+
+    def testEmphasis05(self):
+        test = ur"'''test''test'''''"
+        output = ur"<strong>test<em>test</em></strong>"
+        self.do(test, output)
+
+    def testEmphasis06(self):
+        test = ur"''test'''test'''test''"
+        output = ur"<em>test<strong>test</strong>test</em>"
+        self.do(test, output)
+
+    def testEmphasis07(self):
+        test = ur"'''test''test''test'''"
+        output = ur"<strong>test<em>test</em>test</strong>"
+        self.do(test, output)
+
+    def testEmphasis08(self):
+        test = ur"''test'''''test'''"
+        output = ur"<em>test</em><strong>test</strong>"
+        self.do(test, output)
+
+    def testEmphasis09(self):
+        test = ur"'''test'''''test''"
+        output = ur"<strong>test</strong><em>test</em>"
+        self.do(test, output)
+
+    def testEmphasis10(self):
+        test = ur"'''''test''test'''"
+        output = ur"<strong><em>test</em>test</strong>"
+        self.do(test, output)
+
+    def testEmphasis11(self):
+        test = ur"'''''test'''test''"
+        output = ur"<em><strong>test</strong>test</em>"
+        self.do(test, output)
+
+    def testFormatBig01(self):
+        test = ur"~+test+~"
+        output = ur"<big>test</big>"
+        self.do(test, output)
+
+    def testFormatSmall01(self):
+        test = ur"~-test-~"
+        output = ur"<small>test</small>"
+        self.do(test, output)
+
+    def testFormatStrike01(self):
+        test = ur"--(test)--"
+        output = ur"<strike>test</strike>"
+        self.do(test, output)
+
+    def testFormatSub01(self):
+        test = ur",,test,,"
+        output = ur"<sub>test</sub>"
+        self.do(test, output)
+
+    def testFormatSup01(self):
+        test = ur"^test^"
+        output = ur"<sup>test</sup>"
+        self.do(test, output)
+
+    def testFormatUnderline01(self):
+        test = ur"__test__"
+        output = ur"<u>test</u>"
+        self.do(test, output)
+
+    def testPre01(self):
+        test = ur"{{{test}}}"
+        output = ur"<tt>test</tt>"
+        self.do(test, output)
+
+    def testWhitespace01(self):
+        test = ur"''test '''test'''''"
+        output = ur"<em>test <strong>test</strong></em>"
+        self.do(test, output)
+
+class ConvertInlineItemRepeatableTests(BaseTests):
+    def do(self, text, output):
+        text = text.lstrip('\n')
+        output = output.strip('\n')
+        output = "<p>%s </p>" % output
+        request = MinimalRequest(self.request)
+        page = MinimalPage()
+        formatter = Formatter(request)
+        formatter.setPage(page)
+        Parser(text, request).format(formatter)
+        repeat = ''.join(request.result).strip('\n')
+        self.failUnlessEqual(repeat, output)
+        out = self.do_convert_real([request, page.page_name, repeat])
+        out = out.rstrip('\n')
+        self.failUnlessEqual(text, out)
+
+    def testWikiWord01(self):
+        test = ur"WikiWord"
+        output = ur"""<a class="nonexistent" href="./WikiWord">WikiWord</a>"""
+        self.do(test, output)
+
+    def testNoWikiWord01(self):
+        test = ur"!WikiWord"
+        output = ur"WikiWord"
+        self.do(test, output)
+
+    def testSmiley01(self):
+        test = ur":-)"
+        output = ur"""<img src="/wiki/modern/img/smile.png" alt=":-)" height="15" width="15">"""
+        self.do(test, output)
+
+class StripTests(unittest.TestCase):
+    def do(self, cls, text, output):
+        tree = converter.parse(text)
+        cls().do(tree)
+        out = StringIO()
+        try:
+            import xml.dom.ext
+        except ImportError:
+            raise _tests.TestSkiped('xml.dom.ext module is not available')
+        xml.dom.ext.Print(tree, out)
+        self.failUnlessEqual("<?xml version='1.0' encoding='UTF-8'?>%s" % output, out.getvalue().decode("utf-8"))
+
+class StripBreakTests(StripTests):
+    def do(self, text, output):
+        super(StripBreakTests, self).do(converter.strip_break, text, output)
+
+class StripWhitespaceTests(StripTests):
+    def do(self, text, output):
+        super(StripWhitespaceTests, self).do(converter.strip_whitespace, text, output)
+
+    def test1(self):
+        test = ur"""
+<t/>
+"""
+        output = ur"""<t/>"""
+        self.do(test, output)
+
+    def test2(self):
+        test = ur"""
+<t>
+  <z/>
+</t>
+"""
+        output = ur"""<t><z/></t>"""
+        self.do(test, output)
+
+    def test3(self):
+        test = ur"""
+<t>
+  <z>test</z>
+</t>
+"""
+        output = ur"""<t><z>test</z></t>"""
+        self.do(test, output)
+
+    def test3(self):
+        test = ur"""<p>&nbsp;</p>"""
+        output = ur""""""
+        self.do(test, output)
+
+    def test4(self):
+        test = ur"""<p>test </p>"""
+        output = ur"""<p>test</p>"""
+        self.do(test, output)
+
+class ConvertBrokenBrowserTests(BaseTests):
+    def do(self, text, output):
+        text = text.strip('\n')
+        output = output.lstrip('\n')
+        request = MinimalRequest(self.request)
+        page = MinimalPage()
+        out = self.do_convert_real([request, page.page_name, text])
+        self.failUnlessEqual(output, out)
+
+    def testList01(self):
+        test = ur"""
+<ul>
+<li>test</li>
+<ul>
+<li>test</li>
+</ul>
+<li>test</li>
+</ul>
+"""
+        output = ur"""
+ * test
+  * test
+ * test
+
+"""
+        self.do(test, output)
+
+if __name__ == '__main__':
+    unittest.main()
+
--- a/MoinMoin/_tests/broken/test_converter_text_html_text_x_moin.py	Tue May 16 11:44:24 2006 +1200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1140 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-MoinMoin - MoinMoin.text_html_text_x_moin Tests
-
-@copyright: 2005 by Bastian Blank, ThomasWaldmann
-@license: GNU GPL, see COPYING for details.
-"""
-
-import unittest
-from MoinMoin import _tests
-
-from cStringIO import StringIO
-from MoinMoin.converter import text_html_text_x_moin as converter
-from MoinMoin.parser.wiki import Parser
-from MoinMoin.formatter.text_gedit import Formatter
-from MoinMoin.request import Clock
-
-convert = converter.convert
-error = converter.ConvertError
-
-
-class BaseTests(unittest.TestCase):
-
-    def setUp(self):
-        self.cfg = _tests.TestConfig(self.request, bang_meta=True)
-        
-    def tearDown(self):
-        del self.cfg
-
-    def do_convert_real(self, func_args, successful=True):
-        try:
-            ret = convert(*func_args)
-        except error, e:
-            if successful:
-                self.fail("fails with parse error: %s" % e)
-            else:
-                return
-        if successful:
-            return ret
-        else:
-            self.fail("doesn't fail with parse error")
-
-
-class MinimalPage(object):
-    def __init__(self):
-        self.hilite_re = None
-        self.page_name = "testpage"
-
-
-class MinimalRequest(object):
-    # TODO: do we really need this class? no other test uses a request replacement.
-
-    def __init__(self, request):
-        self.request = request
-        self.clock = Clock()
-        
-        # This is broken - tests that need correct content_lang will fail
-        self.content_lang = None
-        self.current_lang = None
-        
-        self.form = {}
-        self._page_headings = {}
-        self.result = []
-
-    def getText(self, text, formatted=True):
-        return text
-
-    def write(self, text):
-        self.result.append(text)
-
-    def __getattr__(self, name):
-        return getattr(self.request, name)
-
-
-class ConvertBlockRepeatableTests(BaseTests):
-    def do(self, text, output):
-        text = text.lstrip('\n')
-        output = output.strip('\n')
-        request = MinimalRequest(self.request)
-        page = MinimalPage()
-        formatter = Formatter(request)
-        formatter.setPage(page)
-        Parser(text, request).format(formatter)
-        repeat = ''.join(request.result).strip('\n')
-        self.failUnlessEqual(repeat, output)
-        out = self.do_convert_real([request, page.page_name, repeat])
-        self.failUnlessEqual(text, out)
-
-    def testComment01(self):
-        test = ur"""
-##test
-"""
-        output = u"""<pre class="comment">\n##test</pre>"""
-        self.do(test, output)
-
-    def testComment02(self):
-        test = ur"""
-##test
-##test
-"""
-        output = u"""
-<pre class="comment">\n##test</pre>
-<pre class="comment">\n##test</pre>
-"""
-        self.do(test, output)
-
-    def testHeading01(self):
-        test = ur"""
-= test1 =
-
-"""
-        output = ur"""
-<h2>test1</h2>
-"""
-        self.do(test, output)
-
-    def testHeading02(self):
-        test = ur"""
-= test1 =
-
-== test2 ==
-
-"""
-        output = ur"""
-<h2>test1</h2>
-<h3>test2</h3>
-"""
-        self.do(test, output)
-
-    def testListSuccess01(self):
-        test = ur"""
- * test
-
-"""
-        output = ur"""
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testListSuccess02(self):
-        test = ur"""
- 1. test
-
-"""
-        output = ur"""
-<ol type="1">
-<li><p>test </p>
-</li>
-</ol>
-"""
-        self.do(test, output)
-
-    def testListSuccess03(self):
-        test = ur"""
- test:: test
-
-"""
-        output = ur"""
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-"""
-        self.do(test, output)
-
-    def testListSuccess04(self):
-        test = ur"""
- * test
- * test
-
-"""
-        output = ur"""
-<ul>
-<li><p>test </p>
-</li>
-<li><p>test </p>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testListSuccess05(self):
-        test = ur"""
- 1. test
- 1. test
-
-"""
-        output = ur"""
-<ol type="1">
-<li><p>test </p>
-</li>
-<li><p>test </p>
-</li>
-</ol>
-"""
-        self.do(test, output)
-
-    def testListSuccess06(self):
-        test = ur"""
- test:: test
- test:: test
-
-"""
-        output = ur"""
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-"""
-        self.do(test, output)
-
-    def testListSuccess07(self):
-        test = ur"""
- * test
-  
- * test
-
-"""
-        output = ur"""
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testListSuccess08(self):
-        test = ur"""
- 1. test
-  
- 1. test
-
-"""
-        output = ur"""
-<ol type="1">
-<li><p>test </p>
-</li>
-</ol>
-<ol type="1">
-<li><p>test </p>
-</li>
-</ol>
-"""
-        self.do(test, output)
-
-    def testListSuccess09(self):
-        test = ur"""
- test:: test
-  
- test:: test
-
-"""
-        output = ur"""
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-"""
-        self.do(test, output)
-
-    def testListSuccess10(self):
-        test = ur"""
- * test
-  * test
-
-"""
-        output = ur"""
-<ul>
-<li><p>test </p>
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testListSuccess11(self):
-        test = ur"""
- 1. test
-  1. test
-
-"""
-        output = ur"""
-<ol type="1">
-<li><p>test </p>
-<ol type="1">
-<li><p>test </p>
-</li>
-</ol>
-</li>
-</ol>
-"""
-        self.do(test, output)
-
-    def testListSuccess12(self):
-        test = ur"""
- test:: test
-  test:: test
-
-"""
-        output = ur"""
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-</dd>
-</dl>
-"""
-        self.do(test, output)
-
-    def testListSuccess13(self):
-        test = ur"""
- * test
-  * test
- * test
-
-"""
-        output = ur"""
-<ul>
-<li><p>test </p>
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-</li>
-<li><p>test </p>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testListSuccess14(self):
-        test = ur"""
- 1. test
-  1. test
- 1. test
-
-"""
-        output = ur"""
-<ol type="1">
-<li><p>test </p>
-<ol type="1">
-<li><p>test </p>
-</li>
-</ol>
-</li>
-<li><p>test </p>
-</li>
-</ol>
-"""
-        self.do(test, output)
-
-    def testListSuccess15(self):
-        test = ur"""
- test:: test
-  test:: test
- test:: test
-
-"""
-        output = ur"""
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-</dd>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-"""
-        self.do(test, output)
-
-    def testListSuccess16(self):
-        test = ur"""
- * test
-
- 1. test
-
-"""
-        output = ur"""
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-<ol type="1">
-<li><p>test </p>
-</li>
-</ol>
-"""
-        self.do(test, output)
-
-    def testListSuccess17(self):
-        test = ur"""
- * test
-
- test:: test
-
-"""
-        output = ur"""
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-"""
-        self.do(test, output)
-
-    def testListSuccess18(self):
-        test = ur"""
- 1. test
-
- * test
-
-"""
-        output = ur"""
-<ol type="1">
-<li><p>test </p>
-</li>
-</ol>
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testListSuccess19(self):
-        test = ur"""
- 1. test
-
- test:: test
-
-"""
-        output = ur"""
-<ol type="1">
-<li><p>test </p>
-</li>
-</ol>
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-"""
-        self.do(test, output)
-
-    def testListSuccess20(self):
-        test = ur"""
- test:: test
-
- * test
-
-"""
-        output = ur"""
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testListSuccess21(self):
-        test = ur"""
- test:: test
-
- 1. test
-
-"""
-        output = ur"""
-<dl>
-<dt>test</dt>
-<dd><p>test </p>
-</dd>
-</dl>
-<ol type="1">
-<li><p>test </p>
-</li>
-</ol>
-"""
-        self.do(test, output)
-
-    def testListSuccess23(self):
-        test = ur"""
- 1. test
-  * test
-
-"""
-        output = ur"""
-<ol type="1">
-<li><p>test </p>
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-</li>
-</ol>
-"""
-        self.do(test, output)
-
-    def testListSuccess26(self):
-        test = ur"""
- * test
-
-test
-
-"""
-        output = ur"""
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-<p>test </p>
-"""
-        self.do(test, output)
-
-    def testListSuccess28(self):
-        test = ur"""
- * test
-
- test
-
-"""
-        output = ur"""
-<ul>
-<li><p>test </p>
-<p>test </p>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testListSuccess29(self):
-        test = ur"""
- * test
-  * test
- test
-"""
-        output = ur"""
-"""
-        self.do(test, output)
-
-    def testListSuccess30(self):
-        test = ur"""
- * test
-  * test
-  test
-"""
-        output = ur"""
-"""
-        self.do(test, output)
-
-    def testParagraph1(self):
-        test = ur"""
-test
-
-"""
-        output = ur"""
-<p>test </p>
-"""
-        self.do(test, output)
-
-    def testParagraph2(self):
-        test = ur"""
-test
-
-test
-
-"""
-        output = ur"""
-<p>test </p>
-<p>test </p>
-"""
-        self.do(test, output)
-
-    def testPreSuccess1(self):
-        test = ur"""
-{{{
-test
-}}}
-
-"""
-        output = ur"""
-<pre>
-test
-</pre>
-"""
-        self.do(test, output)
-
-    def testPreSuccess2(self):
-        test = ur"""
-{{{
-test
-test
-}}}
-
-"""
-        output = ur"""
-<pre>
-test
-test
-</pre>
-"""
-        self.do(test, output)
-
-    def testPreSuccess3(self):
-        test = ur"""
-{{{
-test
-
-test
-}}}
-
-"""
-        output = ur"""
-<pre>
-test
-
-test
-</pre>
-"""
-        self.do(test, output)
-
-    def testPreSuccess4(self):
-        test = ur"""
-{{{
- * test
-}}}
-
-"""
-        output = ur"""
-<pre>
- * test
-</pre>
-"""
-        self.do(test, output)
-
-    def testPreSuccess5(self):
-        test = ur"""
-{{{
-  }}}
-
-"""
-        output = ur"""
-<pre>
-  </pre>
-"""
-        self.do(test, output)
-
-    def testPreSuccess6(self):
-        test = ur"""
- * {{{
-test
-}}}
-
-"""
-        output = ur"""
-<ul>
-<li>
-<pre>
-test
-</pre>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testPreSuccess7(self):
-        test = ur"""
- * {{{
-   test
-   }}}
-
-"""
-        output = ur"""
-<ul>
-<li>
-<pre>
-   test
-   </pre>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testPreSuccess8(self):
-        test = ur"""
- * test
- {{{
-test
-}}}
-
-"""
-        output = ur"""
-<ul>
-<li><p>test 
-</p>
-<pre>
-test
-</pre>
-</li>
-</ul>
-"""
-        self.do(test, output)
-
-    def testPreSuccess9(self):
-        test = ur"""
- * test
-
-{{{
-test
-}}}
-
-"""
-        output = ur"""
-<ul>
-<li><p>test </p>
-</li>
-</ul>
-
-<pre>
-test
-</pre>
-"""
-        self.do(test, output)
-
-    def testRule1(self):
-        test = ur"""
-----
-
-"""
-        output = ur"""
-<hr/>
-"""
-        self.do(test, output)
-
-    def testTable01(self):
-        test = ur"""
-|| ||
-
-"""
-        output = ur"""
-<div>
-<table>
-<tr>
-<td>
-<p> </p>
-</td>
-</tr>
-</table>
-</div>
-"""
-        self.do(test, output)
-
-    def testTable02(self):
-        test = ur"""
-||test||
-
-"""
-        output = ur"""
-<div>
-<table>
-<tr>
-<td>
-<p>test</p>
-</td>
-</tr>
-</table>
-</div>
-"""
-        self.do(test, output)
-
-    def testTable03(self):
-        test = ur"""
-||test||test||
-
-"""
-        output = ur"""
-<div>
-<table>
-<tr>
-<td>
-<p>test</p>
-</td>
-<td>
-<p>test</p>
-</td>
-</tr>
-</table>
-</div>
-"""
-        self.do(test, output)
-
-    def testTable04(self):
-        test = ur"""
-||test||
-||test||test||
-
-"""
-        output = ur"""
-<div>
-<table>
-<tr>
-<td>
-<p>test</p>
-</td>
-</tr>
-<tr>
-<td>
-<p>test</p>
-</td>
-<td>
-<p>test</p>
-</td>
-</tr>
-</table>
-</div>
-"""
-        self.do(test, output)
-
-    def testTable05(self):
-        test = ur"""
-||||test||
-||test||test||
-
-"""
-        output = ur"""
-<div>
-<table>
-<tr>
-<td colspan="2" style="text-align: center;">
-<p>test</p>
-</td>
-</tr>
-<tr>
-<td>
-<p>test</p>
-</td>
-<td>
-<p>test</p>
-</td>
-</tr>
-</table>
-</div>
-"""
-        self.do(test, output)
-
-    def testTable06(self):
-        test = ur"""
-||||test||test||
-||test||||test||
-
-"""
-        output = ur"""
-<div>
-<table>
-<tr>
-<td colspan="2" style="text-align: center;">
-<p>test</p>
-</td>
-<td>
-<p>test</p>
-</td>
-</tr>
-<tr>
-<td>
-<p>test</p>
-</td>
-<td colspan="2" style="text-align: center;">
-<p>test</p>
-</td>
-</tr>
-</table>
-</div>
-"""
-        self.do(test, output)
-
-class ConvertInlineFormatRepeatableTests(BaseTests):
-    def do(self, text, output):
-        text = text.lstrip('\n')
-        output = output.strip('\n')
-        output = "<p>%s </p>" % output
-        request = MinimalRequest(self.request)
-        page = MinimalPage()
-        formatter = Formatter(request)
-        formatter.setPage(page)
-        Parser(text, request).format(formatter)
-        repeat = ''.join(request.result).strip('\n')
-        self.failUnlessEqual(repeat, output)
-        out = self.do_convert_real([request, page.page_name, repeat])
-        out = out.rstrip('\n')
-        self.failUnlessEqual(text, out)
-
-    def testEmphasis01(self):
-        test = ur"''test''"
-        output = ur"<em>test</em>"
-        self.do(test, output)
-
-    def testEmphasis02(self):
-        test = ur"'''test'''"
-        output = ur"<strong>test</strong>"
-        self.do(test, output)
-
-    def testEmphasis03(self):
-        test = ur"'''''test'''''"
-        output = ur"<em><strong>test</strong></em>"
-        self.do(test, output)
-
-    def testEmphasis04(self):
-        test = ur"''test'''test'''''"
-        output = ur"<em>test<strong>test</strong></em>"
-        self.do(test, output)
-
-    def testEmphasis05(self):
-        test = ur"'''test''test'''''"
-        output = ur"<strong>test<em>test</em></strong>"
-        self.do(test, output)
-
-    def testEmphasis06(self):
-        test = ur"''test'''test'''test''"
-        output = ur"<em>test<strong>test</strong>test</em>"
-        self.do(test, output)
-
-    def testEmphasis07(self):
-        test = ur"'''test''test''test'''"
-        output = ur"<strong>test<em>test</em>test</strong>"
-        self.do(test, output)
-
-    def testEmphasis08(self):
-        test = ur"''test'''''test'''"
-        output = ur"<em>test</em><strong>test</strong>"
-        self.do(test, output)
-
-    def testEmphasis09(self):
-        test = ur"'''test'''''test''"
-        output = ur"<strong>test</strong><em>test</em>"
-        self.do(test, output)
-
-    def testEmphasis10(self):
-        test = ur"'''''test''test'''"
-        output = ur"<strong><em>test</em>test</strong>"
-        self.do(test, output)
-
-    def testEmphasis11(self):
-        test = ur"'''''test'''test''"
-        output = ur"<em><strong>test</strong>test</em>"
-        self.do(test, output)
-
-    def testFormatBig01(self):
-        test = ur"~+test+~"
-        output = ur"<big>test</big>"
-        self.do(test, output)
-
-    def testFormatSmall01(self):
-        test = ur"~-test-~"
-        output = ur"<small>test</small>"
-        self.do(test, output)
-
-    def testFormatStrike01(self):
-        test = ur"--(test)--"
-        output = ur"<strike>test</strike>"
-        self.do(test, output)
-
-    def testFormatSub01(self):
-        test = ur",,test,,"
-        output = ur"<sub>test</sub>"
-        self.do(test, output)
-
-    def testFormatSup01(self):
-        test = ur"^test^"
-        output = ur"<sup>test</sup>"
-        self.do(test, output)
-
-    def testFormatUnderline01(self):
-        test = ur"__test__"
-        output = ur"<u>test</u>"
-        self.do(test, output)
-
-    def testPre01(self):
-        test = ur"{{{test}}}"
-        output = ur"<tt>test</tt>"
-        self.do(test, output)
-
-    def testWhitespace01(self):
-        test = ur"''test '''test'''''"
-        output = ur"<em>test <strong>test</strong></em>"
-        self.do(test, output)
-
-class ConvertInlineItemRepeatableTests(BaseTests):
-    def do(self, text, output):
-        text = text.lstrip('\n')
-        output = output.strip('\n')
-        output = "<p>%s </p>" % output
-        request = MinimalRequest(self.request)
-        page = MinimalPage()
-        formatter = Formatter(request)
-        formatter.setPage(page)
-        Parser(text, request).format(formatter)
-        repeat = ''.join(request.result).strip('\n')
-        self.failUnlessEqual(repeat, output)
-        out = self.do_convert_real([request, page.page_name, repeat])
-        out = out.rstrip('\n')
-        self.failUnlessEqual(text, out)
-
-    def testWikiWord01(self):
-        test = ur"WikiWord"
-        output = ur"""<a class="nonexistent" href="./WikiWord">WikiWord</a>"""
-        self.do(test, output)
-
-    def testNoWikiWord01(self):
-        test = ur"!WikiWord"
-        output = ur"WikiWord"
-        self.do(test, output)
-
-    def testSmiley01(self):
-        test = ur":-)"
-        output = ur"""<img src="/wiki/modern/img/smile.png" alt=":-)" height="15" width="15">"""
-        self.do(test, output)
-
-class StripTests(unittest.TestCase):
-    def do(self, cls, text, output):
-        tree = converter.parse(text)
-        cls().do(tree)
-        out = StringIO()
-        try:
-            import xml.dom.ext
-        except ImportError:
-            raise _tests.TestSkiped('xml.dom.ext module is not available')
-        xml.dom.ext.Print(tree, out)
-        self.failUnlessEqual("<?xml version='1.0' encoding='UTF-8'?>%s" % output, out.getvalue().decode("utf-8"))
-
-class StripBreakTests(StripTests):
-    def do(self, text, output):
-        super(StripBreakTests, self).do(converter.strip_break, text, output)
-
-class StripWhitespaceTests(StripTests):
-    def do(self, text, output):
-        super(StripWhitespaceTests, self).do(converter.strip_whitespace, text, output)
-
-    def test1(self):
-        test = ur"""
-<t/>
-"""
-        output = ur"""<t/>"""
-        self.do(test, output)
-
-    def test2(self):
-        test = ur"""
-<t>
-  <z/>
-</t>
-"""
-        output = ur"""<t><z/></t>"""
-        self.do(test, output)
-
-    def test3(self):
-        test = ur"""
-<t>
-  <z>test</z>
-</t>
-"""
-        output = ur"""<t><z>test</z></t>"""
-        self.do(test, output)
-
-    def test3(self):
-        test = ur"""<p>&nbsp;</p>"""
-        output = ur""""""
-        self.do(test, output)
-
-    def test4(self):
-        test = ur"""<p>test </p>"""
-        output = ur"""<p>test</p>"""
-        self.do(test, output)
-
-class ConvertBrokenBrowserTests(BaseTests):
-    def do(self, text, output):
-        text = text.strip('\n')
-        output = output.lstrip('\n')
-        request = MinimalRequest(self.request)
-        page = MinimalPage()
-        out = self.do_convert_real([request, page.page_name, text])
-        self.failUnlessEqual(output, out)
-
-    def testList01(self):
-        test = ur"""
-<ul>
-<li>test</li>
-<ul>
-<li>test</li>
-</ul>
-<li>test</li>
-</ul>
-"""
-        output = ur"""
- * test
-  * test
- * test
-
-"""
-        self.do(test, output)
-
-if __name__ == '__main__':
-    unittest.main()
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/_tests/broken/test_parser_text_moin_wiki.py	Wed May 17 09:27:26 2006 +1200
@@ -0,0 +1,452 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - MoinMoin.parser.text_moin_wiki Tests
+
+    TODO: these are actually parser+formatter tests. We should have
+    parser only tests here.
+
+    @copyright: 2003-2004 by Jürgen Hermann <jh@web.de>
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import unittest
+import re
+from StringIO import StringIO
+from MoinMoin._tests import TestConfig
+from MoinMoin.Page import Page
+from MoinMoin.parser.wiki import Parser
+
+
+class ParserTestCase(unittest.TestCase):
+    """ Helper class that provide a parsing method """
+    
+    def parse(self, body):
+        """Parse body and return html
+
+        Create a page with body, then parse it and format using html formatter
+        """
+        assert body is not None
+        self.request.reset()
+        page = Page(self.request, 'ThisPageDoesNotExistsAndWillNeverBeReally')
+        page.set_raw_body(body)
+        from MoinMoin.formatter.text_html import Formatter
+        page.formatter = Formatter(self.request)
+        self.request.formatter = page.formatter
+        page.formatter.setPage(page)
+        page.hilite_re = None
+        
+        output = StringIO()
+        saved_write = self.request.write
+        self.request.write = output.write
+        try:
+            Parser(body, self.request).format(page.formatter)
+        finally:
+            self.request.write = saved_write
+        return output.getvalue()
+
+
+class ParagraphsTestCase(ParserTestCase):
+    """ Test paragraphs creating
+
+    All tests ignoring white space in output
+    """
+
+    def testFirstParagraph(self):
+         """ parser.wiki: first paragraph should be in <p> """
+         result = self.parse('First')
+         expected = re.compile(r'<p>\s*First\s*</p>')
+         self.assert_(expected.search(result),
+                      '"%s" not in "%s"' % (expected.pattern, result))
+
+    def testEmptyLineBetweenParagraphs(self):
+        """ parser.wiki: empty line separates paragraphs """
+        result = self.parse('First\n\nSecond')
+        expected = re.compile(r'<p>\s*Second\s*</p>')
+        self.assert_(expected.search(result),
+                     '"%s" not in "%s"' % (expected.pattern, result))
+        
+    def testParagraphAfterBlockMarkup(self):
+        """ parser.wiki: create paragraph after block markup """
+
+        markup = (
+            '----\n',
+            '[[en]]\n',
+            '|| table ||\n',
+            '= heading 1 =\n',
+            '== heading 2 ==\n',
+            '=== heading 3 ===\n',
+            '==== heading 4 ====\n',
+            '===== heading 5 =====\n',
+            )
+        for item in markup:
+            text = item + 'Paragraph'
+            result = self.parse(text)
+            expected = re.compile(r'<p.*?>\s*Paragraph\s*</p>')
+            self.assert_(expected.search(result),
+                         '"%s" not in "%s"' % (expected.pattern, result))
+
+
+class HeadingsTestCase(ParserTestCase):
+    """ Test various heading problems """
+
+    def setUp(self):
+        """ Require show_section_numbers = 0 to workaround counter
+        global state saved in request.
+        """
+        self.config = TestConfig(self.request, show_section_numbers=0)
+    
+    def tearDown(self):
+        del self.config
+
+    def testIgnoreWhiteSpaceAroundHeadingText(self):
+        """ parser.wiki: ignore white space around heading text
+
+        See bug: TableOfContentsBreakOnExtraSpaces.
+
+        Does not test mapping of '=' to h number, or valid html markup.
+        """
+        tests = (
+            '=  head =\n', # leading
+            '= head  =\n', # trailing
+            '=  head  =\n' # both
+                 )
+        expected = self.parse('= head =')
+        for test in tests:            
+            result = self.parse(test)
+            self.assertEqual(result, expected,
+                'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+
+class TOCTestCase(ParserTestCase):
+
+    def setUp(self):
+        """ Require show_section_numbers = 0 to workaround counter
+        global state saved in request.
+        """
+        self.config = TestConfig(self.request, show_section_numbers=0)
+    
+    def tearDown(self):
+        del self.config
+
+    def testHeadingWithWhiteSpace(self):
+        """ parser.wiki: TOC links to headings with white space
+        
+        See bug: TableOfContentsBreakOnExtraSpaces.
+
+        Does not test TOC or heading formating, just verify that spaces
+        around heading text does not matter.
+        """
+        standard = """
+[[TableOfContents]]
+= heading =
+Text
+"""
+        withWhitespace = """
+[[TableOfContents]]
+=   heading   =
+Text
+"""
+        expected = self.parse(standard)
+        result = self.parse(withWhitespace)
+        self.assertEqual(result, expected,
+            'Expected "%(expected)s" but got "%(result)s"' % locals())
+        
+
+class DateTimeMacroTestCase(ParserTestCase):
+   """ Test DateTime macro
+
+   Might fail due to libc problems, therefore the fail message warn
+   about this.
+
+   TODO: when this test fail, does it mean that moin code fail on that
+   machine? - can we fix this?
+   """
+   
+   text = 'XXX %s XXX'
+   needle = re.compile(text %  r'(.+)')
+   _tests = (
+       # test                                   expected
+       ('[[DateTime(1970-01-06T00:00:00)]]',   '1970-01-06 00:00:00'),
+       ('[[DateTime(259200)]]',                '1970-01-04 00:00:00'),
+       ('[[DateTime(2003-03-03T03:03:03)]]',   '2003-03-03 03:03:03'),
+       ('[[DateTime(2000-01-01T00:00:00Z)]]',  '2000-01-01 00:00:00'),
+       ('[[Date(2002-02-02T01:02:03Z)]]',      '2002-02-02'),
+       )
+
+   def setUp(self):
+       """ Require default date and time format config values """
+       self.config = TestConfig(self.request,
+                                defaults=('date_fmt', 'datetime_fmt'))
+   
+   def tearDown(self):
+       del self.config
+   
+   def testDateTimeMacro(self):
+       """ parser.wiki: DateTime macro """
+       note = """
+   
+   If this fails, it is likely a problem in your python / libc,
+   not in moin.  See also:
+   <http://sourceforge.net/tracker/index.php?func=detail&
+       aid=902172&group_id=5470&atid=105470>"""
+
+       for test, expected in self._tests:
+           html = self.parse(self.text % test)
+           result = self.needle.search(html).group(1)
+           self.assertEqual(result, expected,
+               'Expected "%(expected)s" but got "%(result)s"; %(note)s' % locals())
+                       
+
+class TextFormatingTestCase(ParserTestCase):
+    """ Test wiki markup """
+    
+    text = 'XXX %s XXX'
+    needle = re.compile(text %  r'(.+)')
+    _tests = (
+        # test,                     expected
+        ('no format',               'no format'),
+        ("''em''",                  '<em>em</em>'),
+        ("'''bold'''",              '<strong>bold</strong>'),
+        ("__underline__",           '<span class="u">underline</span>'),
+        ("'''''Mix''' at start''",  '<em><strong>Mix</strong> at start</em>'),
+        ("'''''Mix'' at start'''",  '<strong><em>Mix</em> at start</strong>'),
+        ("'''Mix at ''end'''''",    '<strong>Mix at <em>end</em></strong>'),
+        ("''Mix at '''end'''''",    '<em>Mix at <strong>end</strong></em>'),
+        )
+    
+    def testTextFormating(self):
+        """ parser.wiki: text formating """
+        for test, expected in self._tests:
+            html = self.parse(self.text % test)
+            result = self.needle.search(html).group(1)
+            self.assertEqual(result, expected,
+                             'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+
+class CloseInlineTestCase(ParserTestCase):
+
+    def testCloseOneInline(self):
+        """ parser.wiki: close open inline tag when block close """
+        cases = (
+            # test, expected
+            ("text'''text\n", r"<p>text<strong>text\s*</strong></p>"),
+            ("text''text\n", r"<p>text<em>text\s*</em></p>"),
+            ("text__text\n", r"<p>text<span class=\"u\">text\s*</span></p>"),
+            ("text ''em '''em strong __em strong underline",
+             r"text <em>em <strong>em strong <span class=\"u\">em strong underline"
+             r"\s*</span></strong></em></p>"),
+            )
+        for test, expected in cases:
+            needle = re.compile(expected)
+            result = self.parse(test)
+            self.assert_(needle.search(result),
+                         'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+
+class InlineCrossingTestCase(ParserTestCase):
+    """
+    This test case fail with current parser/formatter and should be fixed in 2.0
+    """
+    
+    def disabled_testInlineCrossing(self):
+        """ parser.wiki: prevent inline crossing <a><b></a></b> """
+
+        expected = ("<p><em>a<strong>ab</strong></em><strong>b</strong>\s*</p>")
+        test = "''a'''ab''b'''\n"
+        needle = re.compile(expected)
+        result = self.parse(test)
+        self.assert_(needle.search(result),
+                     'Expected "%(expected)s" but got "%(result)s"' % locals())
+       
+
+class EscapeHTMLTestCase(ParserTestCase):
+    
+    def testEscapeInTT(self):
+        """ parser.wiki: escape html markup in `tt` """
+        test = 'text `<escape-me>` text\n'
+        self._test(test)
+
+    def testEscapeInTT2(self):
+        """ parser.wiki: escape html markup in {{{tt}}} """
+        test = 'text {{{<escape-me>}}} text\n'
+        self._test(test)
+
+    def testEscapeInPre(self):
+        """ parser.wiki: escape html markup in pre """
+        test = '''{{{
+<escape-me>
+}}}
+'''
+        self._test(test)
+        
+    def testEscapeInPreHashbang(self):
+        """ parser.wiki: escape html markup in pre with hashbang """
+        test = '''{{{#!
+<escape-me>
+}}}
+'''
+        self._test(test)
+        
+    def testEscapeInPythonCodeArea(self):
+        """ parser.wiki: escape html markup in python code area """
+        test = '''{{{#!python
+#<escape-me>
+}}}
+'''
+        self._test(test)
+
+    def testEscapeInGetTextMacro(self):
+        """ parser.wiki: escape html markup in GetText macro """
+        test = "text [[GetText(<escape-me>)]] text"
+        self._test(test)
+
+    def testEscapeInGetTextFormatted(self):
+        """ parser.wiki: escape html markup in getText formatted call """
+        test = self.request.getText('<escape-me>', formatted=1)
+        self._test(test)
+
+    def testEscapeInGetTextFormatedLink(self):
+        """ parser.wiki: escape html markup in getText formatted call with link """
+        test = self.request.getText('["<escape-me>"]', formatted=1)
+        self._test(test)
+
+    def testEscapeInGetTextUnFormatted(self):
+        """ parser.wiki: escape html markup in getText non formatted call """
+        test = self.request.getText('<escape-me>', formatted=0)
+        self._test(test)
+
+    def _test(self, test):
+        expected = r'&lt;escape-me&gt;'
+        result = self.parse(test)
+        self.assert_(re.search(expected, result),
+                     'Expected "%(expected)s" but got "%(result)s"' % locals())         
+
+
+class EscapeWikiTableMarkupTestCase(ParserTestCase):
+
+    def testEscapeInTT(self):
+        """ parser.wiki: escape wiki table markup in `tt` """
+        test = 'text `||<tablewidth="80"> Table ||` text\n'
+        self.do(test)
+
+    def testEscapeInTT2(self):
+        """ parser.wiki: escape wiki table markup in {{{tt}}} """
+        test = 'text {{{||<tablewidth="80"> Table ||}}} text\n'
+        self.do(test)
+
+    def testEscapeInPre(self):
+        """ parser.wiki: escape wiki table  markup in pre """
+        test = '''{{{
+||<tablewidth="80"> Table ||
+}}}
+'''
+        self.do(test)
+        
+    def testEscapeInPreHashbang(self):
+        """ parser.wiki: escape wiki table  markup in pre with hashbang """
+        test = '''{{{#!
+||<tablewidth="80"> Table ||
+}}}
+'''
+        self.do(test)
+        
+    def testEscapeInPythonCodeArea(self):
+        """ parser.wiki: escape wiki table markup in python code area """
+        test = '''{{{#!python
+# ||<tablewidth="80"> Table ||
+}}}
+'''
+        self.do(test)
+
+    def do(self, test):
+        expected = r'&lt;tablewidth="80"&gt;'
+        result = self.parse(test)
+        self.assert_(re.search(expected, result),
+                     'Expected "%(expected)s" but got "%(result)s"' % locals())         
+
+
+class RuleTestCase(ParserTestCase):
+    """ Test rules markup """
+
+    def testNotRule(self):
+        """ parser.wiki: --- is no rule """
+        result = self.parse('---')
+        expected = '---' # inside <p>
+        self.assert_(expected in result,
+                     'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+    def testStandardRule(self):
+        """ parser.wiki: ---- is standard rule """
+        result = self.parse('----')
+        expected = '<hr>'
+        self.assert_(expected in result,
+                     'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+    def testVariableRule(self):
+        """ parser.wiki: ----- rules with size """
+
+        for size in range(5, 11):
+            test = '-' * size         
+            result = self.parse(test)
+            expected = '<hr class="hr%d">' % (size - 4)
+            self.assert_(expected in result,
+                     'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+    def testLongRule(self):
+        """ parser.wiki: ------------ long rule shortened to hr6 """
+        test = '-' * 254        
+        result = self.parse(test)
+        expected = '<hr class="hr6">'
+        self.assert_(expected in result,
+                     'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+
+class BlockTestCase(ParserTestCase):
+    cases = (
+        # test, block start
+        ('----\n', '<hr'),
+        ('= Heading =\n', '<h2'),
+        ('{{{\nPre\n}}}\n', '<pre'),
+        ('{{{\n#!python\nPre\n}}}\n', '<div'),
+        ('|| Table ||', '<div'),
+        (' * unordered list\n', '<ul'),
+        (' 1. ordered list\n', '<ol'),
+        (' indented text\n', '<ul'),
+        )
+
+    def testParagraphBeforeBlock(self):
+        """ parser.wiki: paragraph closed before block element """
+        text = """XXX
+%s
+"""
+        for test, blockstart in self.cases:
+            # We dont test here formatter white space generation
+            expected = r'<p>XXX\s*</p>\n+%s' % blockstart
+            needle = re.compile(expected, re.MULTILINE)
+            result = self.parse(text % test)
+            match = needle.search(result)
+            self.assert_(match is not None,
+                         'Expected "%(expected)s" but got "%(result)s"' % locals())
+            
+    def testEmptyLineBeforeBlock(self):
+        """ parser.wiki: empty lines before block element ignored
+        
+        Empty lines separate paragraphs, but should be ignored if a block
+        element follow.
+
+        Currently an empty paragraph is created, which make no sense but
+        no real harm.
+        """
+        text = """XXX
+
+%s
+"""
+        for test, blockstart in self.cases:
+            expected = r'<p>XXX\s*</p>\n+%s' % blockstart
+            needle = re.compile(expected, re.MULTILINE)
+            result = self.parse(text % test)
+            match = needle.search(result)
+            self.assert_(match is not None,
+                         'Expected "%(expected)s" but got "%(result)s"' % locals())
+
+
--- a/MoinMoin/_tests/broken/test_parser_wiki.py	Tue May 16 11:44:24 2006 +1200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,452 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - MoinMoin.parser.wiki Tests
-
-    TODO: these are actually parser+formatter tests. We should have
-    parser only tests here.
-
-    @copyright: 2003-2004 by Jürgen Hermann <jh@web.de>
-    @license: GNU GPL, see COPYING for details.
-"""
-
-import unittest
-import re
-from StringIO import StringIO
-from MoinMoin._tests import TestConfig
-from MoinMoin.Page import Page
-from MoinMoin.parser.wiki import Parser
-
-
-class ParserTestCase(unittest.TestCase):
-    """ Helper class that provide a parsing method """
-    
-    def parse(self, body):
-        """Parse body and return html
-
-        Create a page with body, then parse it and format using html formatter
-        """
-        assert body is not None
-        self.request.reset()
-        page = Page(self.request, 'ThisPageDoesNotExistsAndWillNeverBeReally')
-        page.set_raw_body(body)
-        from MoinMoin.formatter.text_html import Formatter
-        page.formatter = Formatter(self.request)
-        self.request.formatter = page.formatter
-        page.formatter.setPage(page)
-        page.hilite_re = None
-        
-        output = StringIO()
-        saved_write = self.request.write
-        self.request.write = output.write
-        try:
-            Parser(body, self.request).format(page.formatter)
-        finally:
-            self.request.write = saved_write
-        return output.getvalue()
-
-
-class ParagraphsTestCase(ParserTestCase):
-    """ Test paragraphs creating
-
-    All tests ignoring white space in output
-    """
-
-    def testFirstParagraph(self):
-         """ parser.wiki: first paragraph should be in <p> """
-         result = self.parse('First')
-         expected = re.compile(r'<p>\s*First\s*</p>')
-         self.assert_(expected.search(result),
-                      '"%s" not in "%s"' % (expected.pattern, result))
-
-    def testEmptyLineBetweenParagraphs(self):
-        """ parser.wiki: empty line separates paragraphs """
-        result = self.parse('First\n\nSecond')
-        expected = re.compile(r'<p>\s*Second\s*</p>')
-        self.assert_(expected.search(result),
-                     '"%s" not in "%s"' % (expected.pattern, result))
-        
-    def testParagraphAfterBlockMarkup(self):
-        """ parser.wiki: create paragraph after block markup """
-
-        markup = (
-            '----\n',
-            '[[en]]\n',
-            '|| table ||\n',
-            '= heading 1 =\n',
-            '== heading 2 ==\n',
-            '=== heading 3 ===\n',
-            '==== heading 4 ====\n',
-            '===== heading 5 =====\n',
-            )
-        for item in markup:
-            text = item + 'Paragraph'
-            result = self.parse(text)
-            expected = re.compile(r'<p.*?>\s*Paragraph\s*</p>')
-            self.assert_(expected.search(result),
-                         '"%s" not in "%s"' % (expected.pattern, result))
-
-
-class HeadingsTestCase(ParserTestCase):
-    """ Test various heading problems """
-
-    def setUp(self):
-        """ Require show_section_numbers = 0 to workaround counter
-        global state saved in request.
-        """
-        self.config = TestConfig(self.request, show_section_numbers=0)
-    
-    def tearDown(self):
-        del self.config
-
-    def testIgnoreWhiteSpaceAroundHeadingText(self):
-        """ parser.wiki: ignore white space around heading text
-
-        See bug: TableOfContentsBreakOnExtraSpaces.
-
-        Does not test mapping of '=' to h number, or valid html markup.
-        """
-        tests = (
-            '=  head =\n', # leading
-            '= head  =\n', # trailing
-            '=  head  =\n' # both
-                 )
-        expected = self.parse('= head =')
-        for test in tests:            
-            result = self.parse(test)
-            self.assertEqual(result, expected,
-                'Expected "%(expected)s" but got "%(result)s"' % locals())
-
-
-class TOCTestCase(ParserTestCase):
-
-    def setUp(self):
-        """ Require show_section_numbers = 0 to workaround counter
-        global state saved in request.
-        """
-        self.config = TestConfig(self.request, show_section_numbers=0)
-    
-    def tearDown(self):
-        del self.config
-
-    def testHeadingWithWhiteSpace(self):
-        """ parser.wiki: TOC links to headings with white space
-        
-        See bug: TableOfContentsBreakOnExtraSpaces.
-
-        Does not test TOC or heading formating, just verify that spaces
-        around heading text does not matter.
-        """
-        standard = """
-[[TableOfContents]]
-= heading =
-Text
-"""
-        withWhitespace = """
-[[TableOfContents]]
-=   heading   =
-Text
-"""
-        expected = self.parse(standard)
-        result = self.parse(withWhitespace)
-        self.assertEqual(result, expected,
-            'Expected "%(expected)s" but got "%(result)s"' % locals())
-        
-
-class DateTimeMacroTestCase(ParserTestCase):
-   """ Test DateTime macro
-
-   Might fail due to libc problems, therefore the fail message warn
-   about this.
-
-   TODO: when this test fail, does it mean that moin code fail on that
-   machine? - can we fix this?
-   """
-   
-   text = 'XXX %s XXX'
-   needle = re.compile(text %  r'(.+)')
-   _tests = (
-       # test                                   expected
-       ('[[DateTime(1970-01-06T00:00:00)]]',   '1970-01-06 00:00:00'),
-       ('[[DateTime(259200)]]',                '1970-01-04 00:00:00'),
-       ('[[DateTime(2003-03-03T03:03:03)]]',   '2003-03-03 03:03:03'),
-       ('[[DateTime(2000-01-01T00:00:00Z)]]',  '2000-01-01 00:00:00'),
-       ('[[Date(2002-02-02T01:02:03Z)]]',      '2002-02-02'),
-       )
-
-   def setUp(self):
-       """ Require default date and time format config values """
-       self.config = TestConfig(self.request,
-                                defaults=('date_fmt', 'datetime_fmt'))
-   
-   def tearDown(self):
-       del self.config
-   
-   def testDateTimeMacro(self):
-       """ parser.wiki: DateTime macro """
-       note = """
-   
-   If this fails, it is likely a problem in your python / libc,
-   not in moin.  See also:
-   <http://sourceforge.net/tracker/index.php?func=detail&
-       aid=902172&group_id=5470&atid=105470>"""
-
-       for test, expected in self._tests:
-           html = self.parse(self.text % test)
-           result = self.needle.search(html).group(1)
-           self.assertEqual(result, expected,
-               'Expected "%(expected)s" but got "%(result)s"; %(note)s' % locals())
-                       
-
-class TextFormatingTestCase(ParserTestCase):
-    """ Test wiki markup """
-    
-    text = 'XXX %s XXX'
-    needle = re.compile(text %  r'(.+)')
-    _tests = (
-        # test,                     expected
-        ('no format',               'no format'),
-        ("''em''",                  '<em>em</em>'),
-        ("'''bold'''",              '<strong>bold</strong>'),
-        ("__underline__",           '<span class="u">underline</span>'),
-        ("'''''Mix''' at start''",  '<em><strong>Mix</strong> at start</em>'),
-        ("'''''Mix'' at start'''",  '<strong><em>Mix</em> at start</strong>'),
-        ("'''Mix at ''end'''''",    '<strong>Mix at <em>end</em></strong>'),
-        ("''Mix at '''end'''''",    '<em>Mix at <strong>end</strong></em>'),
-        )
-    
-    def testTextFormating(self):
-        """ parser.wiki: text formating """
-        for test, expected in self._tests:
-            html = self.parse(self.text % test)
-            result = self.needle.search(html).group(1)
-            self.assertEqual(result, expected,
-                             'Expected "%(expected)s" but got "%(result)s"' % locals())
-
-
-class CloseInlineTestCase(ParserTestCase):
-
-    def testCloseOneInline(self):
-        """ parser.wiki: close open inline tag when block close """
-        cases = (
-            # test, expected
-            ("text'''text\n", r"<p>text<strong>text\s*</strong></p>"),
-            ("text''text\n", r"<p>text<em>text\s*</em></p>"),
-            ("text__text\n", r"<p>text<span class=\"u\">text\s*</span></p>"),
-            ("text ''em '''em strong __em strong underline",
-             r"text <em>em <strong>em strong <span class=\"u\">em strong underline"
-             r"\s*</span></strong></em></p>"),
-            )
-        for test, expected in cases:
-            needle = re.compile(expected)
-            result = self.parse(test)
-            self.assert_(needle.search(result),
-                         'Expected "%(expected)s" but got "%(result)s"' % locals())
-
-
-class InlineCrossingTestCase(ParserTestCase):
-    """
-    This test case fail with current parser/formatter and should be fixed in 2.0
-    """
-    
-    def disabled_testInlineCrossing(self):
-        """ parser.wiki: prevent inline crossing <a><b></a></b> """
-
-        expected = ("<p><em>a<strong>ab</strong></em><strong>b</strong>\s*</p>")
-        test = "''a'''ab''b'''\n"
-        needle = re.compile(expected)
-        result = self.parse(test)
-        self.assert_(needle.search(result),
-                     'Expected "%(expected)s" but got "%(result)s"' % locals())
-       
-
-class EscapeHTMLTestCase(ParserTestCase):
-    
-    def testEscapeInTT(self):
-        """ parser.wiki: escape html markup in `tt` """
-        test = 'text `<escape-me>` text\n'
-        self._test(test)
-
-    def testEscapeInTT2(self):
-        """ parser.wiki: escape html markup in {{{tt}}} """
-        test = 'text {{{<escape-me>}}} text\n'
-        self._test(test)
-
-    def testEscapeInPre(self):
-        """ parser.wiki: escape html markup in pre """
-        test = '''{{{
-<escape-me>
-}}}
-'''
-        self._test(test)
-        
-    def testEscapeInPreHashbang(self):
-        """ parser.wiki: escape html markup in pre with hashbang """
-        test = '''{{{#!
-<escape-me>
-}}}
-'''
-        self._test(test)
-        
-    def testEscapeInPythonCodeArea(self):
-        """ parser.wiki: escape html markup in python code area """
-        test = '''{{{#!python
-#<escape-me>
-}}}
-'''
-        self._test(test)
-
-    def testEscapeInGetTextMacro(self):
-        """ parser.wiki: escape html markup in GetText macro """
-        test = "text [[GetText(<escape-me>)]] text"
-        self._test(test)
-
-    def testEscapeInGetTextFormatted(self):
-        """ parser.wiki: escape html markup in getText formatted call """
-        test = self.request.getText('<escape-me>', formatted=1)
-        self._test(test)
-
-    def testEscapeInGetTextFormatedLink(self):
-        """ parser.wiki: escape html markup in getText formatted call with link """
-        test = self.request.getText('["<escape-me>"]', formatted=1)
-        self._test(test)
-
-    def testEscapeInGetTextUnFormatted(self):
-        """ parser.wiki: escape html markup in getText non formatted call """
-        test = self.request.getText('<escape-me>', formatted=0)
-        self._test(test)
-
-    def _test(self, test):
-        expected = r'&lt;escape-me&gt;'
-        result = self.parse(test)
-        self.assert_(re.search(expected, result),
-                     'Expected "%(expected)s" but got "%(result)s"' % locals())         
-
-
-class EscapeWikiTableMarkupTestCase(ParserTestCase):
-
-    def testEscapeInTT(self):
-        """ parser.wiki: escape wiki table markup in `tt` """
-        test = 'text `||<tablewidth="80"> Table ||` text\n'
-        self.do(test)
-
-    def testEscapeInTT2(self):
-        """ parser.wiki: escape wiki table markup in {{{tt}}} """
-        test = 'text {{{||<tablewidth="80"> Table ||}}} text\n'
-        self.do(test)
-
-    def testEscapeInPre(self):
-        """ parser.wiki: escape wiki table  markup in pre """
-        test = '''{{{
-||<tablewidth="80"> Table ||
-}}}
-'''
-        self.do(test)
-        
-    def testEscapeInPreHashbang(self):
-        """ parser.wiki: escape wiki table  markup in pre with hashbang """
-        test = '''{{{#!
-||<tablewidth="80"> Table ||
-}}}
-'''
-        self.do(test)
-        
-    def testEscapeInPythonCodeArea(self):
-        """ parser.wiki: escape wiki table markup in python code area """
-        test = '''{{{#!python
-# ||<tablewidth="80"> Table ||
-}}}
-'''
-        self.do(test)
-
-    def do(self, test):
-        expected = r'&lt;tablewidth="80"&gt;'
-        result = self.parse(test)
-        self.assert_(re.search(expected, result),
-                     'Expected "%(expected)s" but got "%(result)s"' % locals())         
-
-
-class RuleTestCase(ParserTestCase):
-    """ Test rules markup """
-
-    def testNotRule(self):
-        """ parser.wiki: --- is no rule """
-        result = self.parse('---')
-        expected = '---' # inside <p>
-        self.assert_(expected in result,
-                     'Expected "%(expected)s" but got "%(result)s"' % locals())
-
-    def testStandardRule(self):
-        """ parser.wiki: ---- is standard rule """
-        result = self.parse('----')
-        expected = '<hr>'
-        self.assert_(expected in result,
-                     'Expected "%(expected)s" but got "%(result)s"' % locals())
-
-    def testVariableRule(self):
-        """ parser.wiki: ----- rules with size """
-
-        for size in range(5, 11):
-            test = '-' * size         
-            result = self.parse(test)
-            expected = '<hr class="hr%d">' % (size - 4)
-            self.assert_(expected in result,
-                     'Expected "%(expected)s" but got "%(result)s"' % locals())
-
-    def testLongRule(self):
-        """ parser.wiki: ------------ long rule shortened to hr6 """
-        test = '-' * 254        
-        result = self.parse(test)
-        expected = '<hr class="hr6">'
-        self.assert_(expected in result,
-                     'Expected "%(expected)s" but got "%(result)s"' % locals())
-
-
-class BlockTestCase(ParserTestCase):
-    cases = (
-        # test, block start
-        ('----\n', '<hr'),
-        ('= Heading =\n', '<h2'),
-        ('{{{\nPre\n}}}\n', '<pre'),
-        ('{{{\n#!python\nPre\n}}}\n', '<div'),
-        ('|| Table ||', '<div'),
-        (' * unordered list\n', '<ul'),
-        (' 1. ordered list\n', '<ol'),
-        (' indented text\n', '<ul'),
-        )
-
-    def testParagraphBeforeBlock(self):
-        """ parser.wiki: paragraph closed before block element """
-        text = """XXX
-%s
-"""
-        for test, blockstart in self.cases:
-            # We dont test here formatter white space generation
-            expected = r'<p>XXX\s*</p>\n+%s' % blockstart
-            needle = re.compile(expected, re.MULTILINE)
-            result = self.parse(text % test)
-            match = needle.search(result)
-            self.assert_(match is not None,
-                         'Expected "%(expected)s" but got "%(result)s"' % locals())
-            
-    def testEmptyLineBeforeBlock(self):
-        """ parser.wiki: empty lines before block element ignored
-        
-        Empty lines separate paragraphs, but should be ignored if a block
-        element follow.
-
-        Currently an empty paragraph is created, which make no sense but
-        no real harm.
-        """
-        text = """XXX
-
-%s
-"""
-        for test, blockstart in self.cases:
-            expected = r'<p>XXX\s*</p>\n+%s' % blockstart
-            needle = re.compile(expected, re.MULTILINE)
-            result = self.parse(text % test)
-            match = needle.search(result)
-            self.assert_(match is not None,
-                         'Expected "%(expected)s" but got "%(result)s"' % locals())
-
-
--- a/MoinMoin/_tests/test_formatter.py	Tue May 16 11:44:24 2006 +1200
+++ b/MoinMoin/_tests/test_formatter.py	Wed May 17 09:27:26 2006 +1200
@@ -11,7 +11,6 @@
 from StringIO import StringIO
 from MoinMoin._tests import TestConfig
 from MoinMoin.Page import Page
-from MoinMoin.parser.wiki import Parser
 from MoinMoin import wikiutil
 
 
--- a/MoinMoin/_tests/test_pysupport.py	Tue May 16 11:44:24 2006 +1200
+++ b/MoinMoin/_tests/test_pysupport.py	Wed May 17 09:27:26 2006 +1200
@@ -26,13 +26,13 @@
     def testNonExistingAttribute(self):
         """ pysupport: import nonexistent attritbue raises AttributeError """
         self.assertRaises(AttributeError, pysupport.importName,
-                          'MoinMoin.parser.wiki','NoSuchParser')
+                          'MoinMoin.parser.text_moin_wiki','NoSuchParser')
 
     def testExisting(self):
         """ pysupport: import name from existing module """
-        from MoinMoin.parser import wiki
-        Parser = pysupport.importName('MoinMoin.parser.wiki', 'Parser')
-        self.failUnless(Parser is wiki.Parser)
+        from MoinMoin.parser import text_moin_wiki
+        Parser = pysupport.importName('MoinMoin.parser.text_moin_wiki', 'Parser')
+        self.failUnless(Parser is text_moin_wiki.Parser)
    
 
 class ImportNameFromPlugin(unittest.TestCase):
@@ -42,11 +42,9 @@
     
     def setUp(self):
         """ Check for valid plugin package """
-        self.pluginDirectory = os.path.join(self.request.cfg.data_dir,
-                                            'plugin', 'parser')
+        self.pluginDirectory = os.path.join(self.request.cfg.data_dir, 'plugin', 'parser')
         self.checkPackage(self.pluginDirectory)
-        self.pluginModule = (self.request.cfg.siteid + '.plugin.parser.' +
-                             self.plugin)
+        self.pluginModule = (self.request.cfg.siteid + '.plugin.parser.' + self.plugin)
 
     def checkPackage(self, path):
         for item in (path, os.path.join(path, '__init__.py')):
@@ -124,5 +122,4 @@
             except OSError, err:
                 if err.errno != errno.ENOENT:
                     raise
-    
-            
\ No newline at end of file
+
--- a/MoinMoin/action/MyPages.py	Tue May 16 11:44:24 2006 +1200
+++ b/MoinMoin/action/MyPages.py	Wed May 17 09:27:26 2006 +1200
@@ -57,7 +57,7 @@
     pagecontent = pagecontent.replace('\n', '\r\n')
 
     from MoinMoin.Page import Page
-    from MoinMoin.parser.wiki import Parser
+    from MoinMoin.parser.text_moin_wiki import Parser as WikiParser
     request.http_headers()
     
     # This action generate data using the user language
@@ -67,7 +67,7 @@
     # Start content - IMPORTANT - without content div, there is no direction support!
     request.write(request.formatter.startContent("content"))
 
-    parser = Parser(pagecontent, request)
+    parser = WikiParser(pagecontent, request)
     p = Page(request, "$$$")
     request.formatter.setPage(p)
     parser.format(request.formatter)
--- a/MoinMoin/action/RenderAsDocbook.py	Tue May 16 11:44:24 2006 +1200
+++ b/MoinMoin/action/RenderAsDocbook.py	Wed May 17 09:27:26 2006 +1200
@@ -8,7 +8,7 @@
 from MoinMoin.Page import Page
 
 def execute(pagename, request):
-    url = Page(request, pagename).url(request, {'action': 'format',
-                                                'mimetype': 'xml/docbook'}, 0)
+    url = Page(request, pagename).url(request, {'action': 'show',
+                                                'mimetype': 'text/docbook'}, 0)
     request.http_redirect(url)
 
--- a/MoinMoin/action/__init__.py	Tue May 16 11:44:24 2006 +1200
+++ b/MoinMoin/action/__init__.py	Wed May 17 09:27:26 2006 +1200
@@ -244,9 +244,8 @@
         Since 5.5.2006 this functionality is also done by do_show, but do_format
         has a default of text/plain when no format is given.
         It also does not count in statistics and also does not set the cacheable flag.
-        TODO: remove this action when we don't need it any more for compatibility.
+        DEPRECATED: remove this action when we don't need it any more for compatibility.
     """
-    # get the MIME type
     if not request.form.has_key('mimetype'):
         request.form['mimetype'] = [u"text/plain"]
     do_show(pagename, request, count_hit=0, cacheable=0)
@@ -365,7 +364,7 @@
     cancelled = request.form.has_key('button_cancel')
 
     # convert input from Graphical editor
-    from MoinMoin.converter.text_html_text_x_moin import convert, ConvertError
+    from MoinMoin.converter.text_html_text_moin_wiki import convert, ConvertError
     try:
         if lasteditor == 'gui':
             savetext = convert(request, pagename, savetext)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/converter/text_html_text_moin_wiki.py	Wed May 17 09:27:26 2006 +1200
@@ -0,0 +1,1220 @@
+"""
+    MoinMoin - convert from html to wiki markup
+
+    @copyright: (c) Bastian Blank, Florian Festi, Thomas Waldmann
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import re, os
+import xml.dom.minidom
+from xml.dom import Node
+
+from MoinMoin import config, wikiutil, error
+
+# Portions (C) International Organization for Standardization 1986
+# Permission to copy in any form is granted for use with
+# conforming SGML systems and applications as defined in
+# ISO 8879, provided this notice is included in all copies.
+dtd = ur'''
+<!DOCTYPE html [
+<!ENTITY nbsp   "&#32;">  <!-- no-break space = non-breaking space, U+00A0, convert to U+0020 -->
+<!ENTITY iexcl  "&#161;"> <!-- inverted exclamation mark, U+00A1 ISOnum -->
+<!ENTITY cent   "&#162;"> <!-- cent sign, U+00A2 ISOnum -->
+<!ENTITY pound  "&#163;"> <!-- pound sign, U+00A3 ISOnum -->
+<!ENTITY curren "&#164;"> <!-- currency sign, U+00A4 ISOnum -->
+<!ENTITY yen    "&#165;"> <!-- yen sign = yuan sign, U+00A5 ISOnum -->
+<!ENTITY brvbar "&#166;"> <!-- broken bar = broken vertical bar, U+00A6 ISOnum -->
+<!ENTITY sect   "&#167;"> <!-- section sign, U+00A7 ISOnum -->
+<!ENTITY uml    "&#168;"> <!-- diaeresis = spacing diaeresis, U+00A8 ISOdia -->
+<!ENTITY copy   "&#169;"> <!-- copyright sign, U+00A9 ISOnum -->
+<!ENTITY ordf   "&#170;"> <!-- feminine ordinal indicator, U+00AA ISOnum -->
+<!ENTITY laquo  "&#171;"> <!-- left-pointing double angle quotation mark = left pointing guillemet, U+00AB ISOnum -->
+<!ENTITY not    "&#172;"> <!-- not sign = angled dash, U+00AC ISOnum -->
+<!ENTITY shy    "&#173;"> <!-- soft hyphen = discretionary hyphen, U+00AD ISOnum -->
+<!ENTITY reg    "&#174;"> <!-- registered sign = registered trade mark sign, U+00AE ISOnum -->
+<!ENTITY macr   "&#175;"> <!-- macron = spacing macron = overline = APL overbar, U+00AF ISOdia -->
+<!ENTITY deg    "&#176;"> <!-- degree sign, U+00B0 ISOnum -->
+<!ENTITY plusmn "&#177;"> <!-- plus-minus sign = plus-or-minus sign, U+00B1 ISOnum -->
+<!ENTITY sup2   "&#178;"> <!-- superscript two = superscript digit two = squared, U+00B2 ISOnum -->
+<!ENTITY sup3   "&#179;"> <!-- superscript three = superscript digit three = cubed, U+00B3 ISOnum -->
+<!ENTITY acute  "&#180;"> <!-- acute accent = spacing acute, U+00B4 ISOdia -->
+<!ENTITY micro  "&#181;"> <!-- micro sign, U+00B5 ISOnum -->
+<!ENTITY para   "&#182;"> <!-- pilcrow sign = paragraph sign, U+00B6 ISOnum -->
+<!ENTITY middot "&#183;"> <!-- middle dot = Georgian comma = Greek middle dot, U+00B7 ISOnum -->
+<!ENTITY cedil  "&#184;"> <!-- cedilla = spacing cedilla, U+00B8 ISOdia -->
+<!ENTITY sup1   "&#185;"> <!-- superscript one = superscript digit one, U+00B9 ISOnum -->
+<!ENTITY ordm   "&#186;"> <!-- masculine ordinal indicator, U+00BA ISOnum -->
+<!ENTITY raquo  "&#187;"> <!-- right-pointing double angle quotation mark = right pointing guillemet, U+00BB ISOnum -->
+<!ENTITY frac14 "&#188;"> <!-- vulgar fraction one quarter = fraction one quarter, U+00BC ISOnum -->
+<!ENTITY frac12 "&#189;"> <!-- vulgar fraction one half = fraction one half, U+00BD ISOnum -->
+<!ENTITY frac34 "&#190;"> <!-- vulgar fraction three quarters = fraction three quarters, U+00BE ISOnum -->
+<!ENTITY iquest "&#191;"> <!-- inverted question mark = turned question mark, U+00BF ISOnum -->
+<!ENTITY Agrave "&#192;"> <!-- latin capital letter A with grave = latin capital letter A grave, U+00C0 ISOlat1 -->
+<!ENTITY Aacute "&#193;"> <!-- latin capital letter A with acute, U+00C1 ISOlat1 -->
+<!ENTITY Acirc  "&#194;"> <!-- latin capital letter A with circumflex, U+00C2 ISOlat1 -->
+<!ENTITY Atilde "&#195;"> <!-- latin capital letter A with tilde, U+00C3 ISOlat1 -->
+<!ENTITY Auml   "&#196;"> <!-- latin capital letter A with diaeresis, U+00C4 ISOlat1 -->
+<!ENTITY Aring  "&#197;"> <!-- latin capital letter A with ring above = latin capital letter A ring, U+00C5 ISOlat1 -->
+<!ENTITY AElig  "&#198;"> <!-- latin capital letter AE = latin capital ligature AE, U+00C6 ISOlat1 -->
+<!ENTITY Ccedil "&#199;"> <!-- latin capital letter C with cedilla, U+00C7 ISOlat1 -->
+<!ENTITY Egrave "&#200;"> <!-- latin capital letter E with grave, U+00C8 ISOlat1 -->
+<!ENTITY Eacute "&#201;"> <!-- latin capital letter E with acute, U+00C9 ISOlat1 -->
+<!ENTITY Ecirc  "&#202;"> <!-- latin capital letter E with circumflex, U+00CA ISOlat1 -->
+<!ENTITY Euml   "&#203;"> <!-- latin capital letter E with diaeresis, U+00CB ISOlat1 -->
+<!ENTITY Igrave "&#204;"> <!-- latin capital letter I with grave, U+00CC ISOlat1 -->
+<!ENTITY Iacute "&#205;"> <!-- latin capital letter I with acute, U+00CD ISOlat1 -->
+<!ENTITY Icirc  "&#206;"> <!-- latin capital letter I with circumflex, U+00CE ISOlat1 -->
+<!ENTITY Iuml   "&#207;"> <!-- latin capital letter I with diaeresis, U+00CF ISOlat1 -->
+<!ENTITY ETH    "&#208;"> <!-- latin capital letter ETH, U+00D0 ISOlat1 -->
+<!ENTITY Ntilde "&#209;"> <!-- latin capital letter N with tilde, U+00D1 ISOlat1 -->
+<!ENTITY Ograve "&#210;"> <!-- latin capital letter O with grave, U+00D2 ISOlat1 -->
+<!ENTITY Oacute "&#211;"> <!-- latin capital letter O with acute, U+00D3 ISOlat1 -->
+<!ENTITY Ocirc  "&#212;"> <!-- latin capital letter O with circumflex, U+00D4 ISOlat1 -->
+<!ENTITY Otilde "&#213;"> <!-- latin capital letter O with tilde, U+00D5 ISOlat1 -->
+<!ENTITY Ouml   "&#214;"> <!-- latin capital letter O with diaeresis, U+00D6 ISOlat1 -->
+<!ENTITY times  "&#215;"> <!-- multiplication sign, U+00D7 ISOnum -->
+<!ENTITY Oslash "&#216;"> <!-- latin capital letter O with stroke = latin capital letter O slash, U+00D8 ISOlat1 -->
+<!ENTITY Ugrave "&#217;"> <!-- latin capital letter U with grave, U+00D9 ISOlat1 -->
+<!ENTITY Uacute "&#218;"> <!-- latin capital letter U with acute, U+00DA ISOlat1 -->
+<!ENTITY Ucirc  "&#219;"> <!-- latin capital letter U with circumflex, U+00DB ISOlat1 -->
+<!ENTITY Uuml   "&#220;"> <!-- latin capital letter U with diaeresis, U+00DC ISOlat1 -->
+<!ENTITY Yacute "&#221;"> <!-- latin capital letter Y with acute, U+00DD ISOlat1 -->
+<!ENTITY THORN  "&#222;"> <!-- latin capital letter THORN, U+00DE ISOlat1 -->
+<!ENTITY szlig  "&#223;"> <!-- latin small letter sharp s = ess-zed, U+00DF ISOlat1 -->
+<!ENTITY agrave "&#224;"> <!-- latin small letter a with grave = latin small letter a grave, U+00E0 ISOlat1 -->
+<!ENTITY aacute "&#225;"> <!-- latin small letter a with acute, U+00E1 ISOlat1 -->
+<!ENTITY acirc  "&#226;"> <!-- latin small letter a with circumflex, U+00E2 ISOlat1 -->
+<!ENTITY atilde "&#227;"> <!-- latin small letter a with tilde, U+00E3 ISOlat1 -->
+<!ENTITY auml   "&#228;"> <!-- latin small letter a with diaeresis, U+00E4 ISOlat1 -->
+<!ENTITY aring  "&#229;"> <!-- latin small letter a with ring above = latin small letter a ring, U+00E5 ISOlat1 -->
+<!ENTITY aelig  "&#230;"> <!-- latin small letter ae = latin small ligature ae, U+00E6 ISOlat1 -->
+<!ENTITY ccedil "&#231;"> <!-- latin small letter c with cedilla, U+00E7 ISOlat1 -->
+<!ENTITY egrave "&#232;"> <!-- latin small letter e with grave, U+00E8 ISOlat1 -->
+<!ENTITY eacute "&#233;"> <!-- latin small letter e with acute, U+00E9 ISOlat1 -->
+<!ENTITY ecirc  "&#234;"> <!-- latin small letter e with circumflex, U+00EA ISOlat1 -->
+<!ENTITY euml   "&#235;"> <!-- latin small letter e with diaeresis, U+00EB ISOlat1 -->
+<!ENTITY igrave "&#236;"> <!-- latin small letter i with grave, U+00EC ISOlat1 -->
+<!ENTITY iacute "&#237;"> <!-- latin small letter i with acute, U+00ED ISOlat1 -->
+<!ENTITY icirc  "&#238;"> <!-- latin small letter i with circumflex, U+00EE ISOlat1 -->
+<!ENTITY iuml   "&#239;"> <!-- latin small letter i with diaeresis, U+00EF ISOlat1 -->
+<!ENTITY eth    "&#240;"> <!-- latin small letter eth, U+00F0 ISOlat1 -->
+<!ENTITY ntilde "&#241;"> <!-- latin small letter n with tilde, U+00F1 ISOlat1 -->
+<!ENTITY ograve "&#242;"> <!-- latin small letter o with grave, U+00F2 ISOlat1 -->
+<!ENTITY oacute "&#243;"> <!-- latin small letter o with acute, U+00F3 ISOlat1 -->
+<!ENTITY ocirc  "&#244;"> <!-- latin small letter o with circumflex, U+00F4 ISOlat1 -->
+<!ENTITY otilde "&#245;"> <!-- latin small letter o with tilde, U+00F5 ISOlat1 -->
+<!ENTITY ouml   "&#246;"> <!-- latin small letter o with diaeresis, U+00F6 ISOlat1 -->
+<!ENTITY divide "&#247;"> <!-- division sign, U+00F7 ISOnum -->
+<!ENTITY oslash "&#248;"> <!-- latin small letter o with stroke, = latin small letter o slash, U+00F8 ISOlat1 -->
+<!ENTITY ugrave "&#249;"> <!-- latin small letter u with grave, U+00F9 ISOlat1 -->
+<!ENTITY uacute "&#250;"> <!-- latin small letter u with acute, U+00FA ISOlat1 -->
+<!ENTITY ucirc  "&#251;"> <!-- latin small letter u with circumflex, U+00FB ISOlat1 -->
+<!ENTITY uuml   "&#252;"> <!-- latin small letter u with diaeresis, U+00FC ISOlat1 -->
+<!ENTITY yacute "&#253;"> <!-- latin small letter y with acute, U+00FD ISOlat1 -->
+<!ENTITY thorn  "&#254;"> <!-- latin small letter thorn, U+00FE ISOlat1 -->
+<!ENTITY yuml   "&#255;"> <!-- latin small letter y with diaeresis, U+00FF ISOlat1 -->
+
+<!-- Latin Extended-B -->
+<!ENTITY fnof     "&#402;"> <!-- latin small f with hook = function                                    = florin, U+0192 ISOtech -->
+
+<!-- Greek -->
+<!ENTITY Alpha    "&#913;"> <!-- greek capital letter alpha, U+0391 -->
+<!ENTITY Beta     "&#914;"> <!-- greek capital letter beta, U+0392 -->
+<!ENTITY Gamma    "&#915;"> <!-- greek capital letter gamma,
+                                    U+0393 ISOgrk3 -->
+<!ENTITY Delta    "&#916;"> <!-- greek capital letter delta,
+                                    U+0394 ISOgrk3 -->
+<!ENTITY Epsilon  "&#917;"> <!-- greek capital letter epsilon, U+0395 -->
+<!ENTITY Zeta     "&#918;"> <!-- greek capital letter zeta, U+0396 -->
+<!ENTITY Eta      "&#919;"> <!-- greek capital letter eta, U+0397 -->
+<!ENTITY Theta    "&#920;"> <!-- greek capital letter theta,
+                                    U+0398 ISOgrk3 -->
+<!ENTITY Iota     "&#921;"> <!-- greek capital letter iota, U+0399 -->
+<!ENTITY Kappa    "&#922;"> <!-- greek capital letter kappa, U+039A -->
+<!ENTITY Lambda   "&#923;"> <!-- greek capital letter lambda,
+                                    U+039B ISOgrk3 -->
+<!ENTITY Mu       "&#924;"> <!-- greek capital letter mu, U+039C -->
+<!ENTITY Nu       "&#925;"> <!-- greek capital letter nu, U+039D -->
+<!ENTITY Xi       "&#926;"> <!-- greek capital letter xi, U+039E ISOgrk3 -->
+<!ENTITY Omicron  "&#927;"> <!-- greek capital letter omicron, U+039F -->
+<!ENTITY Pi       "&#928;"> <!-- greek capital letter pi, U+03A0 ISOgrk3 -->
+<!ENTITY Rho      "&#929;"> <!-- greek capital letter rho, U+03A1 -->
+<!-- there is no Sigmaf, and no U+03A2 character either -->
+<!ENTITY Sigma    "&#931;"> <!-- greek capital letter sigma,
+                                    U+03A3 ISOgrk3 -->
+<!ENTITY Tau      "&#932;"> <!-- greek capital letter tau, U+03A4 -->
+<!ENTITY Upsilon  "&#933;"> <!-- greek capital letter upsilon,
+                                    U+03A5 ISOgrk3 -->
+<!ENTITY Phi      "&#934;"> <!-- greek capital letter phi,
+                                    U+03A6 ISOgrk3 -->
+<!ENTITY Chi      "&#935;"> <!-- greek capital letter chi, U+03A7 -->
+<!ENTITY Psi      "&#936;"> <!-- greek capital letter psi,
+                                    U+03A8 ISOgrk3 -->
+<!ENTITY Omega    "&#937;"> <!-- greek capital letter omega,
+                                    U+03A9 ISOgrk3 -->
+
+<!ENTITY alpha    "&#945;"> <!-- greek small letter alpha,
+                                    U+03B1 ISOgrk3 -->
+<!ENTITY beta     "&#946;"> <!-- greek small letter beta, U+03B2 ISOgrk3 -->
+<!ENTITY gamma    "&#947;"> <!-- greek small letter gamma,
+                                    U+03B3 ISOgrk3 -->
+<!ENTITY delta    "&#948;"> <!-- greek small letter delta,
+                                    U+03B4 ISOgrk3 -->
+<!ENTITY epsilon  "&#949;"> <!-- greek small letter epsilon,
+                                    U+03B5 ISOgrk3 -->
+<!ENTITY zeta     "&#950;"> <!-- greek small letter zeta, U+03B6 ISOgrk3 -->
+<!ENTITY eta      "&#951;"> <!-- greek small letter eta, U+03B7 ISOgrk3 -->
+<!ENTITY theta    "&#952;"> <!-- greek small letter theta,
+                                    U+03B8 ISOgrk3 -->
+<!ENTITY iota     "&#953;"> <!-- greek small letter iota, U+03B9 ISOgrk3 -->
+<!ENTITY kappa    "&#954;"> <!-- greek small letter kappa,
+                                    U+03BA ISOgrk3 -->
+<!ENTITY lambda   "&#955;"> <!-- greek small letter lambda,
+                                    U+03BB ISOgrk3 -->
+<!ENTITY mu       "&#956;"> <!-- greek small letter mu, U+03BC ISOgrk3 -->
+<!ENTITY nu       "&#957;"> <!-- greek small letter nu, U+03BD ISOgrk3 -->
+<!ENTITY xi       "&#958;"> <!-- greek small letter xi, U+03BE ISOgrk3 -->
+<!ENTITY omicron  "&#959;"> <!-- greek small letter omicron, U+03BF NEW -->
+<!ENTITY pi       "&#960;"> <!-- greek small letter pi, U+03C0 ISOgrk3 -->
+<!ENTITY rho      "&#961;"> <!-- greek small letter rho, U+03C1 ISOgrk3 -->
+<!ENTITY sigmaf   "&#962;"> <!-- greek small letter final sigma,
+                                    U+03C2 ISOgrk3 -->
+<!ENTITY sigma    "&#963;"> <!-- greek small letter sigma,
+                                    U+03C3 ISOgrk3 -->
+<!ENTITY tau      "&#964;"> <!-- greek small letter tau, U+03C4 ISOgrk3 -->
+<!ENTITY upsilon  "&#965;"> <!-- greek small letter upsilon,
+                                    U+03C5 ISOgrk3 -->
+<!ENTITY phi      "&#966;"> <!-- greek small letter phi, U+03C6 ISOgrk3 -->
+<!ENTITY chi      "&#967;"> <!-- greek small letter chi, U+03C7 ISOgrk3 -->
+<!ENTITY psi      "&#968;"> <!-- greek small letter psi, U+03C8 ISOgrk3 -->
+<!ENTITY omega    "&#969;"> <!-- greek small letter omega,
+                                    U+03C9 ISOgrk3 -->
+<!ENTITY thetasym "&#977;"> <!-- greek small letter theta symbol,
+                                    U+03D1 NEW -->
+<!ENTITY upsih    "&#978;"> <!-- greek upsilon with hook symbol,
+                                    U+03D2 NEW -->
+<!ENTITY piv      "&#982;"> <!-- greek pi symbol, U+03D6 ISOgrk3 -->
+
+<!-- General Punctuation -->
+<!ENTITY bull     "&#8226;"> <!-- bullet = black small circle,
+                                     U+2022 ISOpub  -->
+<!-- bullet is NOT the same as bullet operator, U+2219 -->
+<!ENTITY hellip   "&#8230;"> <!-- horizontal ellipsis = three dot leader,
+                                     U+2026 ISOpub  -->
+<!ENTITY prime    "&#8242;"> <!-- prime = minutes = feet, U+2032 ISOtech -->
+<!ENTITY Prime    "&#8243;"> <!-- double prime = seconds = inches,
+                                     U+2033 ISOtech -->
+<!ENTITY oline    "&#8254;"> <!-- overline = spacing overscore,
+                                     U+203E NEW -->
+<!ENTITY frasl    "&#8260;"> <!-- fraction slash, U+2044 NEW -->
+
+<!-- Letterlike Symbols -->
+<!ENTITY weierp   "&#8472;"> <!-- script capital P = power set
+                                     = Weierstrass p, U+2118 ISOamso -->
+<!ENTITY image    "&#8465;"> <!-- blackletter capital I = imaginary part,
+                                     U+2111 ISOamso -->
+<!ENTITY real     "&#8476;"> <!-- blackletter capital R = real part symbol,
+                                     U+211C ISOamso -->
+<!ENTITY trade    "&#8482;"> <!-- trade mark sign, U+2122 ISOnum -->
+<!ENTITY alefsym  "&#8501;"> <!-- alef symbol = first transfinite cardinal,
+                                     U+2135 NEW -->
+<!-- alef symbol is NOT the same as hebrew letter alef,
+     U+05D0 although the same glyph could be used to depict both characters -->
+
+<!-- Arrows -->
+<!ENTITY larr     "&#8592;"> <!-- leftwards arrow, U+2190 ISOnum -->
+<!ENTITY uarr     "&#8593;"> <!-- upwards arrow, U+2191 ISOnum-->
+<!ENTITY rarr     "&#8594;"> <!-- rightwards arrow, U+2192 ISOnum -->
+<!ENTITY darr     "&#8595;"> <!-- downwards arrow, U+2193 ISOnum -->
+<!ENTITY harr     "&#8596;"> <!-- left right arrow, U+2194 ISOamsa -->
+<!ENTITY crarr    "&#8629;"> <!-- downwards arrow with corner leftwards
+                                     = carriage return, U+21B5 NEW -->
+<!ENTITY lArr     "&#8656;"> <!-- leftwards double arrow, U+21D0 ISOtech -->
+<!-- ISO 10646 does not say that lArr is the same as the 'is implied by' arrow
+    but also does not have any other character for that function. So ? lArr can
+    be used for 'is implied by' as ISOtech suggests -->
+<!ENTITY uArr     "&#8657;"> <!-- upwards double arrow, U+21D1 ISOamsa -->
+<!ENTITY rArr     "&#8658;"> <!-- rightwards double arrow,
+                                     U+21D2 ISOtech -->
+<!-- ISO 10646 does not say this is the 'implies' character but does not have
+     another character with this function so ?
+     rArr can be used for 'implies' as ISOtech suggests -->
+<!ENTITY dArr     "&#8659;"> <!-- downwards double arrow, U+21D3 ISOamsa -->
+<!ENTITY hArr     "&#8660;"> <!-- left right double arrow,
+                                     U+21D4 ISOamsa -->
+
+<!-- Mathematical Operators -->
+<!ENTITY forall   "&#8704;"> <!-- for all, U+2200 ISOtech -->
+<!ENTITY part     "&#8706;"> <!-- partial differential, U+2202 ISOtech  -->
+<!ENTITY exist    "&#8707;"> <!-- there exists, U+2203 ISOtech -->
+<!ENTITY empty    "&#8709;"> <!-- empty set = null set = diameter,
+                                     U+2205 ISOamso -->
+<!ENTITY nabla    "&#8711;"> <!-- nabla = backward difference,
+                                     U+2207 ISOtech -->
+<!ENTITY isin     "&#8712;"> <!-- element of, U+2208 ISOtech -->
+<!ENTITY notin    "&#8713;"> <!-- not an element of, U+2209 ISOtech -->
+<!ENTITY ni       "&#8715;"> <!-- contains as member, U+220B ISOtech -->
+<!-- should there be a more memorable name than 'ni'? -->
+<!ENTITY prod     "&#8719;"> <!-- n-ary product = product sign,
+                                     U+220F ISOamsb -->
+<!-- prod is NOT the same character as U+03A0 'greek capital letter pi' though
+     the same glyph might be used for both -->
+<!ENTITY sum      "&#8721;"> <!-- n-ary sumation, U+2211 ISOamsb -->
+<!-- sum is NOT the same character as U+03A3 'greek capital letter sigma'
+     though the same glyph might be used for both -->
+<!ENTITY minus    "&#8722;"> <!-- minus sign, U+2212 ISOtech -->
+<!ENTITY lowast   "&#8727;"> <!-- asterisk operator, U+2217 ISOtech -->
+<!ENTITY radic    "&#8730;"> <!-- square root = radical sign,
+                                     U+221A ISOtech -->
+<!ENTITY prop     "&#8733;"> <!-- proportional to, U+221D ISOtech -->
+<!ENTITY infin    "&#8734;"> <!-- infinity, U+221E ISOtech -->
+<!ENTITY ang      "&#8736;"> <!-- angle, U+2220 ISOamso -->
+<!ENTITY and      "&#8743;"> <!-- logical and = wedge, U+2227 ISOtech -->
+<!ENTITY or       "&#8744;"> <!-- logical or = vee, U+2228 ISOtech -->
+<!ENTITY cap      "&#8745;"> <!-- intersection = cap, U+2229 ISOtech -->
+<!ENTITY cup      "&#8746;"> <!-- union = cup, U+222A ISOtech -->
+<!ENTITY int      "&#8747;"> <!-- integral, U+222B ISOtech -->
+<!ENTITY there4   "&#8756;"> <!-- therefore, U+2234 ISOtech -->
+<!ENTITY sim      "&#8764;"> <!-- tilde operator = varies with = similar to,
+                                     U+223C ISOtech -->
+<!-- tilde operator is NOT the same character as the tilde, U+007E,
+     although the same glyph might be used to represent both  -->
+<!ENTITY cong     "&#8773;"> <!-- approximately equal to, U+2245 ISOtech -->
+<!ENTITY asymp    "&#8776;"> <!-- almost equal to = asymptotic to,
+                                     U+2248 ISOamsr -->
+<!ENTITY ne       "&#8800;"> <!-- not equal to, U+2260 ISOtech -->
+<!ENTITY equiv    "&#8801;"> <!-- identical to, U+2261 ISOtech -->
+<!ENTITY le       "&#8804;"> <!-- less-than or equal to, U+2264 ISOtech -->
+<!ENTITY ge       "&#8805;"> <!-- greater-than or equal to,
+                                     U+2265 ISOtech -->
+<!ENTITY sub      "&#8834;"> <!-- subset of, U+2282 ISOtech -->
+<!ENTITY sup      "&#8835;"> <!-- superset of, U+2283 ISOtech -->
+<!-- note that nsup, 'not a superset of, U+2283' is not covered by the Symbol
+     font encoding and is not included. Should it be, for symmetry?
+     It is in ISOamsn  -->
+<!ENTITY nsub     "&#8836;"> <!-- not a subset of, U+2284 ISOamsn -->
+<!ENTITY sube     "&#8838;"> <!-- subset of or equal to, U+2286 ISOtech -->
+<!ENTITY supe     "&#8839;"> <!-- superset of or equal to,
+                                     U+2287 ISOtech -->
+<!ENTITY oplus    "&#8853;"> <!-- circled plus = direct sum,
+                                     U+2295 ISOamsb -->
+<!ENTITY otimes   "&#8855;"> <!-- circled times = vector product,
+                                     U+2297 ISOamsb -->
+<!ENTITY perp     "&#8869;"> <!-- up tack = orthogonal to = perpendicular,
+                                     U+22A5 ISOtech -->
+<!ENTITY sdot     "&#8901;"> <!-- dot operator, U+22C5 ISOamsb -->
+<!-- dot operator is NOT the same character as U+00B7 middle dot -->
+
+<!-- Miscellaneous Technical -->
+<!ENTITY lceil    "&#8968;"> <!-- left ceiling = apl upstile,
+                                     U+2308 ISOamsc  -->
+<!ENTITY rceil    "&#8969;"> <!-- right ceiling, U+2309 ISOamsc  -->
+<!ENTITY lfloor   "&#8970;"> <!-- left floor = apl downstile,
+                                     U+230A ISOamsc  -->
+<!ENTITY rfloor   "&#8971;"> <!-- right floor, U+230B ISOamsc  -->
+<!ENTITY lang     "&#9001;"> <!-- left-pointing angle bracket = bra,
+                                     U+2329 ISOtech -->
+<!-- lang is NOT the same character as U+003C 'less than'
+     or U+2039 'single left-pointing angle quotation mark' -->
+<!ENTITY rang     "&#9002;"> <!-- right-pointing angle bracket = ket,
+                                     U+232A ISOtech -->
+<!-- rang is NOT the same character as U+003E 'greater than'
+     or U+203A 'single right-pointing angle quotation mark' -->
+
+<!-- Geometric Shapes -->
+<!ENTITY loz      "&#9674;"> <!-- lozenge, U+25CA ISOpub -->
+
+<!-- Miscellaneous Symbols -->
+<!ENTITY spades   "&#9824;"> <!-- black spade suit, U+2660 ISOpub -->
+<!-- black here seems to mean filled as opposed to hollow -->
+<!ENTITY clubs    "&#9827;"> <!-- black club suit = shamrock,
+                                     U+2663 ISOpub -->
+<!ENTITY hearts   "&#9829;"> <!-- black heart suit = valentine,
+                                     U+2665 ISOpub -->
+<!ENTITY diams    "&#9830;"> <!-- black diamond suit, U+2666 ISOpub -->
+
+<!-- C0 Controls and Basic Latin -->
+<!ENTITY quot    "&#34;"> <!-- quotation mark = APL quote,
+                                    U+0022 ISOnum -->
+<!ENTITY amp     "&#38;"> <!-- ampersand, U+0026 ISOnum -->
+<!ENTITY lt      "&#60;"> <!-- less-than sign, U+003C ISOnum -->
+<!ENTITY gt      "&#62;"> <!-- greater-than sign, U+003E ISOnum -->
+
+<!-- Latin Extended-A -->
+<!ENTITY OElig   "&#338;"> <!-- latin capital ligature OE,
+                                    U+0152 ISOlat2 -->
+<!ENTITY oelig   "&#339;"> <!-- latin small ligature oe, U+0153 ISOlat2 -->
+<!-- ligature is a misnomer, this is a separate character in some languages -->
+<!ENTITY Scaron  "&#352;"> <!-- latin capital letter S with caron,
+                                    U+0160 ISOlat2 -->
+<!ENTITY scaron  "&#353;"> <!-- latin small letter s with caron,
+                                    U+0161 ISOlat2 -->
+<!ENTITY Yuml    "&#376;"> <!-- latin capital letter Y with diaeresis,
+                                    U+0178 ISOlat2 -->
+
+<!-- Spacing Modifier Letters -->
+<!ENTITY circ    "&#710;"> <!-- modifier letter circumflex accent,
+                                    U+02C6 ISOpub -->
+<!ENTITY tilde   "&#732;"> <!-- small tilde, U+02DC ISOdia -->
+
+<!-- General Punctuation -->
+<!ENTITY ensp    "&#8194;"> <!-- en space, U+2002 ISOpub -->
+<!ENTITY emsp    "&#8195;"> <!-- em space, U+2003 ISOpub -->
+<!ENTITY thinsp  "&#8201;"> <!-- thin space, U+2009 ISOpub -->
+<!ENTITY zwnj    "&#8204;"> <!-- zero width non-joiner,
+                                    U+200C NEW RFC 2070 -->
+<!ENTITY zwj     "&#8205;"> <!-- zero width joiner, U+200D NEW RFC 2070 -->
+<!ENTITY lrm     "&#8206;"> <!-- left-to-right mark, U+200E NEW RFC 2070 -->
+<!ENTITY rlm     "&#8207;"> <!-- right-to-left mark, U+200F NEW RFC 2070 -->
+<!ENTITY ndash   "&#8211;"> <!-- en dash, U+2013 ISOpub -->
+<!ENTITY mdash   "&#8212;"> <!-- em dash, U+2014 ISOpub -->
+<!ENTITY lsquo   "&#8216;"> <!-- left single quotation mark,
+                                    U+2018 ISOnum -->
+<!ENTITY rsquo   "&#8217;"> <!-- right single quotation mark,
+                                    U+2019 ISOnum -->
+<!ENTITY sbquo   "&#8218;"> <!-- single low-9 quotation mark, U+201A NEW -->
+<!ENTITY ldquo   "&#8220;"> <!-- left double quotation mark,
+                                    U+201C ISOnum -->
+<!ENTITY rdquo   "&#8221;"> <!-- right double quotation mark,
+                                    U+201D ISOnum -->
+<!ENTITY bdquo   "&#8222;"> <!-- double low-9 quotation mark, U+201E NEW -->
+<!ENTITY dagger  "&#8224;"> <!-- dagger, U+2020 ISOpub -->
+<!ENTITY Dagger  "&#8225;"> <!-- double dagger, U+2021 ISOpub -->
+<!ENTITY permil  "&#8240;"> <!-- per mille sign, U+2030 ISOtech -->
+<!ENTITY lsaquo  "&#8249;"> <!-- single left-pointing angle quotation mark,
+                                    U+2039 ISO proposed -->
+<!-- lsaquo is proposed but not yet ISO standardized -->
+<!ENTITY rsaquo  "&#8250;"> <!-- single right-pointing angle quotation mark,
+                                    U+203A ISO proposed -->
+<!-- rsaquo is proposed but not yet ISO standardized -->
+<!ENTITY euro   "&#8364;"> <!-- euro sign, U+20AC NEW -->
+
+]>
+'''
+
+class ConvertError(error.FatalError):
+    """ Raise when html to wiki conversion fails """
+    name = "MoinMoin Convert Error"
+    
+
+class visitor(object):
+    def do(self, tree):
+        self.visit_node_list(tree.childNodes)
+
+    def visit_node_list(self, nodelist):
+        for node in nodelist:
+            self.visit(node)
+
+    def visit(self, node):
+        nodeType = node.nodeType
+        if node.nodeType == Node.ELEMENT_NODE:
+            return self.visit_element(node)
+        elif node.nodeType == Node.ATTRIBUTE_NODE:
+            return self.visit_attribute(node)
+        elif node.nodeType == Node.TEXT_NODE:
+            return self.visit_text(node)
+        elif node.nodeType == Node.CDATA_SECTION_NODE:
+            return self.visit_cdata_section(node)
+
+    def visit_element(self, node):
+        if len(node.childNodes):
+            self.visit_node_list(node.childNodes)
+
+    def visit_attribute(self, node):
+        pass
+	
+    def visit_text(self, node):
+        pass
+
+    def visit_cdata_section(self, node):
+        pass
+
+
+class strip_whitespace(visitor):
+
+    def visit_element(self, node):
+        if node.localName == 'p':
+            # XXX: our formatter adds a whitespace at the end of each paragraph
+            if node.hasChildNodes() and node.childNodes[-1].nodeType == Node.TEXT_NODE:
+                data = node.childNodes[-1].data.rstrip('\n ')
+                # Remove it if empty
+                if data == '':
+                    node.removeChild(node.childNodes[-1])
+                else:
+                    node.childNodes[-1].data = data
+            # Remove empty paragraphs
+            if not node.hasChildNodes():
+                node.parentNode.removeChild(node)
+
+        if node.hasChildNodes():
+            self.visit_node_list(node.childNodes)
+
+
+class convert_tree(visitor):
+    white_space = object()
+    new_line = object()
+        
+    def __init__(self, request, pagename):
+        self.request = request
+        self.pagename = pagename
+    
+    def do(self, tree):
+        self.depth = 0
+        self.text = []
+        self.visit(tree.documentElement)
+        self.check_whitespace()
+        return ''.join(self.text)
+
+    def check_whitespace(self):
+        i = 0
+        text = self.text
+        while i < len(text):
+            if text[i] is self.white_space:
+                if i == 0 or i == len(text)-1:
+                    del text[i]
+                elif text[i-1].endswith(" ") or text[i-1].endswith("\n"):
+                    # last char of previous element is whitespace
+                    del text[i]
+                elif (text[i+1] is self.white_space or
+                      # next element is white_space
+                      text[i+1] is self.new_line):
+                      # or new_line
+                    del text[i]
+                elif text[i+1].startswith(" ") or text[i+1].startswith("\n"):
+                    # first char of next element is whitespace
+                    del text[i]
+                else:
+                    text[i] = " "
+                    i += 1
+            elif text[i] is self.new_line:
+                if i == 0:
+                    del text[i]
+                elif i == len(text) - 1:
+                    text[i] = "\n"
+                    i += 1
+                elif text[i-1].endswith("\n") or (
+                      isinstance(text[i+1], str) and text[i+1].startswith("\n")):
+                    del text[i]
+                else:
+                    text[i] = "\n"
+                    i += 1
+            else:
+                i += 1
+
+    def visit_text(self, node):
+        self.text.append(node.data)
+
+    def visit_element(self, node):
+        name = node.localName
+        if name is None: # not sure this can happen here (DOM comment node), but just for the case
+            return
+        func = getattr(self, "process_%s" % name,  None)
+        if func:
+            func(node)
+        else:
+            self.process_inline(node)
+
+    def visit_node_list_element_only(self, nodelist):
+        for node in nodelist:
+            if node.nodeType == Node.ELEMENT_NODE:
+                self.visit_element(node)
+
+    def node_list_text_only(self, nodelist):
+        result = []
+        for node in nodelist:
+            if node.nodeType == Node.TEXT_NODE:
+                result.append(node.data)
+            else:
+                result.extend(self.node_list_text_only(node.childNodes))
+        return "".join(result)
+
+    def process_page(self, node):
+        for i in node.childNodes:
+            if i.nodeType == Node.ELEMENT_NODE:
+                self.visit_element(i)
+            elif i.nodeType == Node.TEXT_NODE: # if this is missing, all std text under a headline is dropped!
+                txt = i.data.strip() # IMPORTANT: don't leave this unstripped or there will be wrong blanks
+                if txt:
+                    self.text.append(txt)
+            #we use <pre class="comment"> now, so this is currently unused:
+            #elif i.nodeType == Node.COMMENT_NODE:
+            #    self.text.append(i.data)
+            #    self.text.append("\n")
+
+    def process_br(self, node):
+            self.text.append(self.new_line) # without this, std multi-line text below some heading misses a whitespace
+                                            # when it gets merged to float text, like word word wordword word word
+
+    def process_heading(self, node):
+        text = self.node_list_text_only(node.childNodes).strip()
+        if text:
+            depth = int(node.localName[1]) - 1
+            hstr = "=" * depth
+            self.text.append(self.new_line)
+            self.text.append("%s %s %s" % (hstr, text.replace("\n", " "), hstr))
+            self.text.append(self.new_line)
+    
+    process_h1 = process_heading
+    process_h2 = process_heading
+    process_h3 = process_heading
+    process_h4 = process_heading
+    process_h5 = process_heading
+    process_h6 = process_heading
+
+    def _get_list_item_markup(self, list, listitem):
+        before = ""
+        #indent = str(self.depth) * self.depth # nice for debugging :)
+        indent = " " * self.depth
+        markup = ""
+        name = list.localName
+        if name == 'ol':
+            class_ = listitem.getAttribute("class")
+            if class_ == "gap":
+                before = "\n"
+            if list.hasAttribute("type"):
+                type = list.getAttribute("type")
+            else:
+                type = "1"
+            markup = "%s. " % type
+        elif name == 'ul':
+            class_ = listitem.getAttribute("class")
+            if class_ == "gap":
+                before = "\n"
+            style = listitem.getAttribute("style")
+            if re.match(u"list-style-type:\s*none", style, re.I):
+                markup = ". "
+            else:
+                markup = "* "
+        elif name == 'dl':
+            markup = ":: "
+        else:
+            raise ConvertError("Illegal list type %s" % name)
+        return before, indent, markup
+
+    def process_dl(self, node):
+        self.depth += 1
+        markup = ":: " # can there be a dl dd without dt?
+        for i in node.childNodes:
+            if i.nodeType == Node.ELEMENT_NODE:
+                name = i.localName
+                if name == 'dt':
+                    before, indent, markup = self._get_list_item_markup(node, i)
+                    self.text.append(before+indent)
+                    text = self.node_list_text_only(i.childNodes)
+                    self.text.append(text.replace("\n", " "))
+                elif name == 'dd':
+                    self.text.append(markup)
+                    self.process_list_item(i, indent)
+                else:
+                    raise ConvertError("Illegal list element %s" % i.localName)
+        self.depth -= 1
+        if self.depth == 0:
+            self.text.append(self.new_line)
+
+    def process_list(self, node):
+        self.depth += 1
+        for i in node.childNodes:
+            if i.nodeType == Node.ELEMENT_NODE:
+                name = i.localName
+                if name == 'li':
+                    before, indent, markup = self._get_list_item_markup(node, i)
+                    self.text.append(before+indent+markup)
+                    self.process_list_item(i, indent)
+                elif name in ('ol', 'ul',):
+                    self.process_list(i)
+                elif name == 'dl':
+                    self.process_dl(i)
+                else:
+                    raise ConvertError("Illegal list element %s" % i.localName)
+        self.depth -= 1
+        if self.depth == 0:
+            self.text.append(self.new_line)
+
+    process_ul = process_list
+    process_ol = process_list
+
+    def empty_paragraph_queue(self, nodelist, indent, need_indent):
+        if need_indent:
+            self.text.append(indent)
+        for i in nodelist:
+            if i.nodeType == Node.ELEMENT_NODE:
+                self.process_inline(i)
+            elif i.nodeType == Node.TEXT_NODE:
+                self.text.append(i.data.strip('\n').replace('\n', ' '))
+        self.text.append(self.new_line)
+        del nodelist[:]
+
+    def process_list_item(self, node, indent):
+        found = False
+        need_indent = False
+        pending = []
+        for i in node.childNodes:
+            name = i.localName
+
+            if name in ('p', 'pre', 'ol', 'ul', 'dl', 'table',) and pending:
+                self.empty_paragraph_queue(pending, indent, need_indent)
+                need_indent = True
+                
+            if name == 'p':
+                if need_indent:
+                    self.text.append(indent)
+                self.process_paragraph_item(i)
+                self.text.append(self.new_line)
+                found = True
+            elif name == 'pre':
+                if need_indent:
+                    self.text.append(indent)
+                self.process_preformatted_item(i)
+                found = True
+            elif name in ('ol', 'ul',):
+                self.process_list(i)
+                found = True
+            elif name == 'dl':
+                self.process_dl(i)
+                found = True
+            elif name == 'table':
+                if need_indent:
+                    self.text.append(indent)
+                self.process_table(i)
+                found = True
+            else:
+                pending.append(i)
+
+            if found:
+                need_indent = True
+
+        if pending:
+            self.empty_paragraph_queue(pending, indent, need_indent)
+
+    def process_blockquote(self, node):
+        # XXX this does not really work. e.g.:
+        # <bq>aaaaaa
+        # <hr---------->
+        # <bq>bbbbbb
+        self.depth += 1
+        for i in node.childNodes:
+            if i.nodeType == Node.ELEMENT_NODE:
+                name = i.localName
+                if name == 'p':
+                    self.text.append(self.new_line)
+                    self.text.append(" " * self.depth)
+                    self.process_p(i)
+                elif name == 'pre':
+                    self.text.append(self.new_line)
+                    self.text.append(" " * self.depth)
+                    self.process_pre(i)
+                elif name in ('h1', 'h2', 'h3', 'h4', 'h5', 'h6',):
+                    self.process_heading(i)
+                elif name in ('ol', 'ul',):
+                    self.process_list(i)
+                elif name == 'dl':
+                    self.process_dl(i)
+                elif name == 'img':
+                    self.process_img(i)
+                elif name == 'div':
+                    self.visit_node_list_element_only(i.childNodes)
+                elif name == 'blockquote':
+                    self.process_blockquote(i)
+                elif name == 'hr':
+                    self.process_hr(i)
+                elif name == 'br':
+                    self.process_br(i)
+                else:
+                    raise ConvertError("process_blockquote: Don't support %s element" % name)
+        self.depth -= 1
+
+    def process_inline(self, node):
+        if node.nodeType == Node.TEXT_NODE:
+            self.text.append(node.data.strip('\n').replace('\n',' '))
+            return
+
+        name = node.localName # can be None for DOM Comment nodes
+        if name is None:
+            return
+
+        if name in ('h1', 'h2', 'h3', 'h4', 'h5', 'h6',): # headers are not allowed here (e.g. inside a ul li),
+            text = self.node_list_text_only(node.childNodes).strip() # but can be inserted via the editor
+            self.text.append(text)                          # so we just drop the header markup and keep the text
+            return
+        
+        func = getattr(self, "process_%s" % name,  None)
+        if func:
+            func(node)
+            return
+
+        command_close = None
+        if name in ('em', 'i',):
+            command = "''"
+        elif name in ('strong', 'b',):
+            command = "'''"
+        elif name == 'u':
+            command = "__"
+        elif name == 'big':
+            command = "~+"
+            command_close = "+~"
+        elif name == 'small':
+            command = "~-"
+            command_close = "-~"
+        elif name == 'strike':
+            command = "--("
+            command_close = ")--"
+        elif name == 'sub':
+            command = ",,"
+        elif name == 'sup':
+            command = "^"
+        elif name == 'font':
+            command = "" # just throw away font settings
+        else:
+            raise ConvertError("process_inline: Don't support %s element" % name)
+        
+        self.text.append(command)
+        for i in node.childNodes:
+            if i.nodeType == Node.ELEMENT_NODE:
+                self.process_inline(i)
+            elif i.nodeType == Node.TEXT_NODE:
+                self.text.append(i.data.strip('\n').replace('\n',' '))
+        if command_close:
+            command = command_close
+        self.text.append(command)
+
+    def process_span(self, node):
+        # ignore span tags - just descend
+        is_strike = node.getAttribute("class") == "strike"
+        if is_strike:
+            self.text.append("--(")
+        for i in node.childNodes:
+            self.process_inline(i)
+        if is_strike:
+            self.text.append(")--")
+
+    def process_div(self, node):
+        # ignore div tags - just descend
+        for i in node.childNodes:
+            self.visit_element(i)
+
+    def process_tt(self, node):
+        text = self.node_list_text_only(node.childNodes).replace("\n", " ")
+        if node.getAttribute("css") == "backtick":
+            self.text.append("`%s`" % text)
+        else:
+            self.text.append("{{{%s}}}" % text)
+
+    def process_hr(self, node):
+        if node.hasAttribute("class"):
+            class_ = node.getAttribute("class")
+        else:
+            class_ = "hr0"
+        if class_.startswith("hr") and class_[2] in "123456":
+            length = int(class_[2]) + 4
+        else:
+            length = 4
+        self.text.extend([self.new_line, "-" * length, self.new_line])
+
+    def process_p(self, node):
+        self.process_paragraph_item(node)
+        self.text.append("\n\n") # do not use self.new_line here!
+
+    def process_paragraph_item(self, node):
+        for i in node.childNodes:
+            if i.nodeType == Node.ELEMENT_NODE:
+                self.process_inline(i)
+            elif i.nodeType == Node.TEXT_NODE:
+                self.text.append(i.data.strip('\n').replace('\n', ' '))
+
+    def process_pre(self, node):
+        self.process_preformatted_item(node)
+        self.text.append(self.new_line)
+
+    def process_preformatted_item(self, node):
+        if node.hasAttribute("class"):
+            class_ = node.getAttribute("class")
+        else:
+            class_ = None
+        if class_ == "comment": # we currently use this for stuff like ## or #acl
+            for i in node.childNodes:
+                if i.nodeType == Node.TEXT_NODE:
+                    self.text.append(i.data)
+                    #print "'%s'" % i.data
+                elif i.localName == 'br':
+                    self.text.append(self.new_line)
+                else:
+                    pass
+                    #print i.localName
+        else:
+            self.text.extend(["{{{", self.new_line])
+            for i in node.childNodes:
+                if i.nodeType == Node.TEXT_NODE:
+                    self.text.append(i.data)
+                    #print "'%s'" % i.data
+                elif i.localName == 'br':
+                    self.text.append(self.new_line)
+                else:
+                    pass
+                    #print i.localName
+            self.text.extend(["}}}", self.new_line])
+
+    _alignment = {"left" : "(",
+                  "center" : ":",
+                  "right" : ")",
+                  "top" : "^",
+                  "bottom" : "v"}
+
+    def _check_length(self, value):
+        try:
+            int(value)
+            return value + 'px'
+        except ValueError:
+            return value
+
+    def _table_style(self, node):
+        result = []
+        if node.hasAttribute("bgcolor"):
+            value = node.getAttribute("bgcolor")
+            match = re.match(r"rgb\((\d+),\s*(\d+),\s*(\d+)\)", value)
+            if match:
+                result.append('tablebgcolor="#%X%X%X"' %
+                              (int(match.group(1)),
+                               int(match.group(2)),
+                               int(match.group(3))))
+            else:
+                result.append('tablebgcolor="%s"' % value)
+        if node.hasAttribute("width"):
+            value = node.getAttribute("width")
+            result.append('tablewidth="%s"' % self._check_length(value))
+        if node.hasAttribute("height"):
+            value = node.getAttribute("height")
+            result.append('tableheight="%s"' % self._check_length(value))
+        if node.hasAttribute("align"):
+            value = node.getAttribute("align")
+            result.append('tablealign="%s"' % value)
+        if node.hasAttribute("style"):
+            result.append('tablestyle="%s"' % node.getAttribute("style"))
+        if node.hasAttribute("class"):
+            result.append('tableclass="%s"' % node.getAttribute("class"))
+        return " ".join(result).strip()
+
+    def _row_style(self, node):
+        result = []
+        if node.hasAttribute("bgcolor"):
+            value = node.getAttribute("bgcolor")
+            match = re.match(r"rgb\((\d+),\s*(\d+),\s*(\d+)\)", value)
+            if match:
+                result.append('rowbgcolor="#%X%X%X"' %
+                              (int(match.group(1)),
+                               int(match.group(2)),
+                               int(match.group(3))))
+            else:
+                result.append('rowbgcolor="%s"' % value)
+        if node.hasAttribute("style"):
+            result.append('rowstyle="%s"' % node.getAttribute("style"))
+        return " ".join(result).strip()
+
+    def _cell_style(self, node):
+        if node.hasAttribute("rowspan"):
+            rowspan = ("|%s" % node.getAttribute("rowspan"))
+        else:
+            rowspan = ""
+
+        if node.hasAttribute("colspan"):
+            colspan = int(node.getAttribute("colspan"))
+        else:
+            colspan = 1
+
+        spanning = rowspan or colspan > 1
+        
+        align = ""
+        result = []
+        if  node.hasAttribute("bgcolor"):
+            value = node.getAttribute("bgcolor")
+            match = re.match(r"rgb\((\d+),\s*(\d+),\s*(\d+)\)", value)
+            if match:
+                result.append("#%X%X%X" % (int(match.group(1)),
+                                           int(match.group(2)),
+                                           int(match.group(3))))
+            else:
+                result.append('bgcolor="%s"' % value)
+        if node.hasAttribute("align"):
+            value = node.getAttribute("align")
+            if not spanning or value != "center":
+                # ignore "center" in spanning cells
+                align += self._alignment.get(value, "")
+        if node.hasAttribute("valign"):
+            value = node.getAttribute("valign")
+            if not spanning or value != "center":
+                # ignore "center" in spanning cells
+                align += self._alignment.get(value, "")
+        if node.hasAttribute("width"):
+            value = node.getAttribute("width")
+            if value[-1] == "%":
+                align += value
+            else:
+                result.append('width="%s"' % self._check_length(value))
+        if node.hasAttribute("height"):
+            value = node.getAttribute("height")
+            result.append('height="%s"' % self._check_length(value))
+        if node.hasAttribute("class"):
+            result.append('class="%s"' % node.getAttribute("class"))
+        if node.hasAttribute("id"):
+            result.append('id="%s"' % node.getAttribute("id"))
+        if node.hasAttribute("style"):
+            result.append('style="%s"' % node.getAttribute("style"))
+                
+        if align:
+            result[0:0] = "%s" % align
+        result.append(rowspan)
+        return " ".join(result).strip()
+
+    def process_table(self, node, style=""):
+        self.text.append(self.new_line)
+        self.new_table = True
+        style += self._table_style(node)
+        for i in node.childNodes:
+            if i.nodeType == Node.ELEMENT_NODE:
+                name = i.localName
+                if name == 'tr':
+                    self.process_table_record(i, style)
+                    style = ""
+                elif name in ('thead', 'tbody', 'tfoot'):
+                    self.process_table(i, style)
+                elif name == 'caption':
+                    self.process_caption(node, i, style)
+                    style = ''
+                else:
+                    raise ConvertError("process_table: Don't support %s element" % name)
+            #else:
+            #    raise ConvertError("Unexpected node: %r" % i)
+        self.text.append(self.new_line)
+
+    def process_caption(self, table, node, style=""):
+        # get first row
+        for i in table.childNodes:
+            if i.localName in ('thead', 'tbody', 'tfoot'): # XXX is this correct?
+            #if i.localName == 'tbody': (old version)
+                for i in i.childNodes:
+                    if i.localName == 'tr':
+                        break
+                break
+            elif i.localName == 'tr':
+                break
+        # count columns
+        if i.localName == 'tr':
+            colspan = 0
+            for td in i.childNodes:
+                if not td.nodeType == Node.ELEMENT_NODE:
+                    continue
+                span = td.getAttribute('colspan')
+                try:
+                    colspan += int(span)
+                except ValueError:
+                    colspan += 1
+        else:
+            colspan = 1
+        text = self.node_list_text_only(node.childNodes).replace('\n', ' ').strip()
+        if text:
+            self.text.extend(["%s'''%s%s'''||" % ('||' * colspan, style, text), self.new_line])
+
+    def process_table_data(self, node, style=""):
+        if node.hasAttribute("colspan"):
+            colspan = int(node.getAttribute("colspan"))
+        else:
+            colspan = 1
+        self.text.append("||" * colspan)
+
+        style += self._cell_style(node)
+        if style:
+            self.text.append("<%s>" % style)
+
+        found = False
+        for i in node.childNodes:
+            name = i.localName
+            if name == 'p':
+                self.process_paragraph_item(i)
+                self.text.append(self.white_space)
+                found = True
+        if not found:
+            for i in node.childNodes:
+                if i.nodeType == Node.ELEMENT_NODE:
+                    self.process_inline(i)
+                    found = True
+                elif i.nodeType == Node.TEXT_NODE:
+                    data = i.data.strip('\n').replace('\n',' ')
+                    if data:
+                        found = True
+                        self.text.append(data)
+        if not found:
+            self.text.append(" ")
+
+    def process_table_record(self, node, style=""):
+        if not self.new_table:
+            self.text.append(" " * self.depth)
+        else:
+            self.new_table = False
+        style += self._row_style(node)
+        for i in node.childNodes:
+            if i.nodeType == Node.ELEMENT_NODE:
+                name = i.localName
+                if name == 'td':
+                    self.process_table_data(i, style=style)
+                    style = ""
+                else:
+                    raise ConvertError("process_table_record: Don't support %s element" % name)
+        self.text.extend(["||", self.new_line])
+
+    def process_a(self, node):
+        scriptname = self.request.getScriptname()
+        if scriptname == "":
+            scriptname = "/"
+        # can either be a link (with href) or an anchor (with e.g. id)
+        href = node.attributes.get("href", None)
+        if href:
+            href = wikiutil.url_unquote(href.nodeValue)
+        id = node.attributes.get("id", None)
+        if id:
+            id = id.nodeValue
+        
+        if href:
+            title = class_ = interwikiname = None
+
+            if node.attributes.has_key("title"):
+                title = node.attributes.get("title").nodeValue
+            if node.attributes.has_key("class"):
+                class_ = node.attributes.get("class").nodeValue
+
+            text = self.node_list_text_only(node.childNodes)
+            text = text.replace("\n", " ").lstrip()
+
+             # interwiki link
+            if class_ == "interwiki":
+                wikitag, wikiurl, wikitail, err = wikiutil.resolve_wiki(
+                    self.request, title + ":")
+                if not err and href.startswith(wikiurl):
+                    pagename = href[len(wikiurl):].lstrip('/')
+                    interwikiname = "%s:%s" % (wikitag, pagename)
+                else: 
+                    raise ConvertError("Invalid InterWiki link: '%s'" % href)
+            elif class_ == "badinterwiki" and title:
+                if href == "/": # we used this as replacement for empty href
+                    href = ""
+                pagename = href
+                interwikiname = "%s:%s" % (title, href)
+            if interwikiname and pagename == text: 
+                self.text.append("%s" % interwikiname)
+                return
+            elif title == 'Self':
+                self.text.append("[:%s:%s]" % (href, text))
+                return
+            elif interwikiname:
+                self.text.append("[wiki:%s %s]" % (interwikiname, text))
+                return
+            
+            # fix links generated by a broken copy & paste of gecko based browsers
+            brokenness = '../../../..'
+            if href.startswith(brokenness):
+                href = href[len(brokenness):] # just strip it away!
+            # TODO: IE pastes complete http://server/Page/SubPage as href and as text, too
+
+            # Attachments
+            if title and title.startswith("attachment:"):
+                url = wikiutil.url_unquote(title[len("attachment:"):])
+                if url != text:
+                    self.text.append("[%s %s]" % (title, text))
+                else:
+                    self.text.extend([self.white_space, title, self.white_space])
+            # wiki link
+            elif href.startswith(scriptname):
+                pagename = href[len(scriptname):].replace('_', ' ')
+                pagename = pagename.lstrip('/')    # XXX temp fix for generated pagenames starting with /
+                if text == pagename:
+                    self.text.append(wikiutil.pagelinkmarkup(pagename))
+                # relative link /SubPage
+                elif href.endswith(text):
+                    if pagename.startswith(self.pagename): # is this a subpage of us?
+                        self.text.append(wikiutil.pagelinkmarkup(pagename[len(self.pagename):]))
+                    else:
+                        self.text.append(wikiutil.pagelinkmarkup(pagename))
+                # relative link ../
+                elif href.endswith(text.lstrip("..").lstrip("/")):
+                    self.text.append(wikiutil.pagelinkmarkup(text))
+                # labeled link
+                else:
+                    self.text.append("[:%s:%s]" % (pagename, text))
+            # mailto link
+            elif href.startswith("mailto:"):
+                if href[len("mailto:"):] == text:
+                    self.text.extend([self.white_space, text, self.white_space])
+                else:
+                    self.text.append("[%s %s]" % (href, text))
+            # simple link
+            elif href.replace(" ", "%20") == text:
+                self.text.append("%s" % text)
+            # imagelink
+            elif text == "" and wikiutil.isPicture(href):
+                self.text.append("[%s]" % href)
+            # labeled link
+            else:
+                href = href.replace(" ", "%20")
+                self.text.append("[%s %s]" % (href, text))
+        elif id:
+            pass # we dont support anchors yet
+
+    def process_img(self, node):
+        src = None
+        if node.attributes.has_key("src"):
+            src = wikiutil.url_unquote(node.attributes.get("src").nodeValue)
+        title = None
+        if node.attributes.has_key("title"):
+            title = node.attributes.get("title").nodeValue
+        alt = None
+        if node.attributes.has_key("alt"):
+            alt = node.attributes.get("alt").nodeValue
+
+        # Attachment image
+        if (title and title.startswith("attachment:") and
+            wikiutil.isPicture(wikiutil.url_unquote(title[len("attachment:"):]))):
+            self.text.extend([self.white_space,
+                              wikiutil.url_unquote(title),
+                              self.white_space])
+        # Drawing image
+        elif title and title.startswith("drawing:"):
+            self.text.extend([self.white_space,
+                              wikiutil.url_unquote(title),
+                              self.white_space])
+        # Smiley
+        elif src and (self.request.cfg.url_prefix in src or '../' in src) and "img/" in src: # XXX this is dirty!
+            filename = src.split("/")[-1]
+            for name, data in config.smileys.iteritems():
+                if data[3] == filename:
+                    self.text.extend([self.white_space, name, self.white_space])
+                    return
+                else:
+                    pass #print name, data, filename, alt
+            raise ConvertError("Unknown smiley icon '%s'" % filename)
+        # Image URL
+        elif src and src.startswith("http") and wikiutil.isPicture(src): # matches http: and https: !
+            self.text.extend([self.white_space, src, self.white_space])
+        else:
+            raise ConvertError("Strange image src: '%s'" % src)
+
+
+def parse(request, text):
+    text = u'<?xml version="1.0"?>%s%s' % (dtd, text)
+    text = text.encode(config.charset)
+    try:
+        return xml.dom.minidom.parseString(text)
+    except xml.parsers.expat.ExpatError, msg:
+        # this sometimes crashes when it should not, so save the stuff to analyze it:
+        logname = os.path.join(request.cfg.data_dir, "expaterror.log")
+        f = file(logname, "w")
+        f.write(text)
+        f.write("\n" + "-"*80 + "\n" + str(msg))
+        f.close()
+        raise ConvertError('ExpatError: %s (see dump in %s)' % (msg, logname))
+
+def convert(request, pagename, text):
+    text = u"<page>%s</page>" % text
+    tree = parse(request, text)
+    strip_whitespace().do(tree)
+    text = convert_tree(request, pagename).do(tree)
+    text = '\n'.join([s.rstrip() for s in text.splitlines()] + ['']) # remove trailing blanks
+    return text
+
--- a/MoinMoin/converter/text_html_text_x_moin.py	Tue May 16 11:44:24 2006 +1200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1213 +0,0 @@
-"""
-    MoinMoin - convert from html to wiki markup
-
-    @copyright: (c) Bastian Blank, Florian Festi, Thomas Waldmann
-    @license: GNU GPL, see COPYING for details.
-"""
-
-import re, os
-import xml.dom.minidom
-from xml.dom import Node
-
-from MoinMoin import config, wikiutil, error
-
-# Portions (C) International Organization for Standardization 1986
-# Permission to copy in any form is granted for use with
-# conforming SGML systems and applications as defined in
-# ISO 8879, provided this notice is included in all copies.
-dtd = ur'''
-<!DOCTYPE html [
-<!ENTITY nbsp   "&#32;">  <!-- no-break space = non-breaking space, U+00A0, convert to U+0020 -->
-<!ENTITY iexcl  "&#161;"> <!-- inverted exclamation mark, U+00A1 ISOnum -->
-<!ENTITY cent   "&#162;"> <!-- cent sign, U+00A2 ISOnum -->
-<!ENTITY pound  "&#163;"> <!-- pound sign, U+00A3 ISOnum -->
-<!ENTITY curren "&#164;"> <!-- currency sign, U+00A4 ISOnum -->
-<!ENTITY yen    "&#165;"> <!-- yen sign = yuan sign, U+00A5 ISOnum -->
-<!ENTITY brvbar "&#166;"> <!-- broken bar = broken vertical bar, U+00A6 ISOnum -->
-<!ENTITY sect   "&#167;"> <!-- section sign, U+00A7 ISOnum -->
-<!ENTITY uml    "&#168;"> <!-- diaeresis = spacing diaeresis, U+00A8 ISOdia -->
-<!ENTITY copy   "&#169;"> <!-- copyright sign, U+00A9 ISOnum -->
-<!ENTITY ordf   "&#170;"> <!-- feminine ordinal indicator, U+00AA ISOnum -->
-<!ENTITY laquo  "&#171;"> <!-- left-pointing double angle quotation mark = left pointing guillemet, U+00AB ISOnum -->
-<!ENTITY not    "&#172;"> <!-- not sign = angled dash, U+00AC ISOnum -->
-<!ENTITY shy    "&#173;"> <!-- soft hyphen = discretionary hyphen, U+00AD ISOnum -->
-<!ENTITY reg    "&#174;"> <!-- registered sign = registered trade mark sign, U+00AE ISOnum -->
-<!ENTITY macr   "&#175;"> <!-- macron = spacing macron = overline = APL overbar, U+00AF ISOdia -->
-<!ENTITY deg    "&#176;"> <!-- degree sign, U+00B0 ISOnum -->
-<!ENTITY plusmn "&#177;"> <!-- plus-minus sign = plus-or-minus sign, U+00B1 ISOnum -->
-<!ENTITY sup2   "&#178;"> <!-- superscript two = superscript digit two = squared, U+00B2 ISOnum -->
-<!ENTITY sup3   "&#179;"> <!-- superscript three = superscript digit three = cubed, U+00B3 ISOnum -->
-<!ENTITY acute  "&#180;"> <!-- acute accent = spacing acute, U+00B4 ISOdia -->
-<!ENTITY micro  "&#181;"> <!-- micro sign, U+00B5 ISOnum -->
-<!ENTITY para   "&#182;"> <!-- pilcrow sign = paragraph sign, U+00B6 ISOnum -->
-<!ENTITY middot "&#183;"> <!-- middle dot = Georgian comma = Greek middle dot, U+00B7 ISOnum -->
-<!ENTITY cedil  "&#184;"> <!-- cedilla = spacing cedilla, U+00B8 ISOdia -->
-<!ENTITY sup1   "&#185;"> <!-- superscript one = superscript digit one, U+00B9 ISOnum -->
-<!ENTITY ordm   "&#186;"> <!-- masculine ordinal indicator, U+00BA ISOnum -->
-<!ENTITY raquo  "&#187;"> <!-- right-pointing double angle quotation mark = right pointing guillemet, U+00BB ISOnum -->
-<!ENTITY frac14 "&#188;"> <!-- vulgar fraction one quarter = fraction one quarter, U+00BC ISOnum -->
-<!ENTITY frac12 "&#189;"> <!-- vulgar fraction one half = fraction one half, U+00BD ISOnum -->
-<!ENTITY frac34 "&#190;"> <!-- vulgar fraction three quarters = fraction three quarters, U+00BE ISOnum -->
-<!ENTITY iquest "&#191;"> <!-- inverted question mark = turned question mark, U+00BF ISOnum -->
-<!ENTITY Agrave "&#192;"> <!-- latin capital letter A with grave = latin capital letter A grave, U+00C0 ISOlat1 -->
-<!ENTITY Aacute "&#193;"> <!-- latin capital letter A with acute, U+00C1 ISOlat1 -->
-<!ENTITY Acirc  "&#194;"> <!-- latin capital letter A with circumflex, U+00C2 ISOlat1 -->
-<!ENTITY Atilde "&#195;"> <!-- latin capital letter A with tilde, U+00C3 ISOlat1 -->
-<!ENTITY Auml   "&#196;"> <!-- latin capital letter A with diaeresis, U+00C4 ISOlat1 -->
-<!ENTITY Aring  "&#197;"> <!-- latin capital letter A with ring above = latin capital letter A ring, U+00C5 ISOlat1 -->
-<!ENTITY AElig  "&#198;"> <!-- latin capital letter AE = latin capital ligature AE, U+00C6 ISOlat1 -->
-<!ENTITY Ccedil "&#199;"> <!-- latin capital letter C with cedilla, U+00C7 ISOlat1 -->
-<!ENTITY Egrave "&#200;"> <!-- latin capital letter E with grave, U+00C8 ISOlat1 -->
-<!ENTITY Eacute "&#201;"> <!-- latin capital letter E with acute, U+00C9 ISOlat1 -->
-<!ENTITY Ecirc  "&#202;"> <!-- latin capital letter E with circumflex, U+00CA ISOlat1 -->
-<!ENTITY Euml   "&#203;"> <!-- latin capital letter E with diaeresis, U+00CB ISOlat1 -->
-<!ENTITY Igrave "&#204;"> <!-- latin capital letter I with grave, U+00CC ISOlat1 -->
-<!ENTITY Iacute "&#205;"> <!-- latin capital letter I with acute, U+00CD ISOlat1 -->
-<!ENTITY Icirc  "&#206;"> <!-- latin capital letter I with circumflex, U+00CE ISOlat1 -->
-<!ENTITY Iuml   "&#207;"> <!-- latin capital letter I with diaeresis, U+00CF ISOlat1 -->
-<!ENTITY ETH    "&#208;"> <!-- latin capital letter ETH, U+00D0 ISOlat1 -->
-<!ENTITY Ntilde "&#209;"> <!-- latin capital letter N with tilde, U+00D1 ISOlat1 -->
-<!ENTITY Ograve "&#210;"> <!-- latin capital letter O with grave, U+00D2 ISOlat1 -->
-<!ENTITY Oacute "&#211;"> <!-- latin capital letter O with acute, U+00D3 ISOlat1 -->
-<!ENTITY Ocirc  "&#212;"> <!-- latin capital letter O with circumflex, U+00D4 ISOlat1 -->
-<!ENTITY Otilde "&#213;"> <!-- latin capital letter O with tilde, U+00D5 ISOlat1 -->
-<!ENTITY Ouml   "&#214;"> <!-- latin capital letter O with diaeresis, U+00D6 ISOlat1 -->
-<!ENTITY times  "&#215;"> <!-- multiplication sign, U+00D7 ISOnum -->
-<!ENTITY Oslash "&#216;"> <!-- latin capital letter O with stroke = latin capital letter O slash, U+00D8 ISOlat1 -->
-<!ENTITY Ugrave "&#217;"> <!-- latin capital letter U with grave, U+00D9 ISOlat1 -->
-<!ENTITY Uacute "&#218;"> <!-- latin capital letter U with acute, U+00DA ISOlat1 -->
-<!ENTITY Ucirc  "&#219;"> <!-- latin capital letter U with circumflex, U+00DB ISOlat1 -->
-<!ENTITY Uuml   "&#220;"> <!-- latin capital letter U with diaeresis, U+00DC ISOlat1 -->
-<!ENTITY Yacute "&#221;"> <!-- latin capital letter Y with acute, U+00DD ISOlat1 -->
-<!ENTITY THORN  "&#222;"> <!-- latin capital letter THORN, U+00DE ISOlat1 -->
-<!ENTITY szlig  "&#223;"> <!-- latin small letter sharp s = ess-zed, U+00DF ISOlat1 -->
-<!ENTITY agrave "&#224;"> <!-- latin small letter a with grave = latin small letter a grave, U+00E0 ISOlat1 -->
-<!ENTITY aacute "&#225;"> <!-- latin small letter a with acute, U+00E1 ISOlat1 -->
-<!ENTITY acirc  "&#226;"> <!-- latin small letter a with circumflex, U+00E2 ISOlat1 -->
-<!ENTITY atilde "&#227;"> <!-- latin small letter a with tilde, U+00E3 ISOlat1 -->
-<!ENTITY auml   "&#228;"> <!-- latin small letter a with diaeresis, U+00E4 ISOlat1 -->
-<!ENTITY aring  "&#229;"> <!-- latin small letter a with ring above = latin small letter a ring, U+00E5 ISOlat1 -->
-<!ENTITY aelig  "&#230;"> <!-- latin small letter ae = latin small ligature ae, U+00E6 ISOlat1 -->
-<!ENTITY ccedil "&#231;"> <!-- latin small letter c with cedilla, U+00E7 ISOlat1 -->
-<!ENTITY egrave "&#232;"> <!-- latin small letter e with grave, U+00E8 ISOlat1 -->
-<!ENTITY eacute "&#233;"> <!-- latin small letter e with acute, U+00E9 ISOlat1 -->
-<!ENTITY ecirc  "&#234;"> <!-- latin small letter e with circumflex, U+00EA ISOlat1 -->
-<!ENTITY euml   "&#235;"> <!-- latin small letter e with diaeresis, U+00EB ISOlat1 -->
-<!ENTITY igrave "&#236;"> <!-- latin small letter i with grave, U+00EC ISOlat1 -->
-<!ENTITY iacute "&#237;"> <!-- latin small letter i with acute, U+00ED ISOlat1 -->
-<!ENTITY icirc  "&#238;"> <!-- latin small letter i with circumflex, U+00EE ISOlat1 -->
-<!ENTITY iuml   "&#239;"> <!-- latin small letter i with diaeresis, U+00EF ISOlat1 -->
-<!ENTITY eth    "&#240;"> <!-- latin small letter eth, U+00F0 ISOlat1 -->
-<!ENTITY ntilde "&#241;"> <!-- latin small letter n with tilde, U+00F1 ISOlat1 -->
-<!ENTITY ograve "&#242;"> <!-- latin small letter o with grave, U+00F2 ISOlat1 -->
-<!ENTITY oacute "&#243;"> <!-- latin small letter o with acute, U+00F3 ISOlat1 -->
-<!ENTITY ocirc  "&#244;"> <!-- latin small letter o with circumflex, U+00F4 ISOlat1 -->
-<!ENTITY otilde "&#245;"> <!-- latin small letter o with tilde, U+00F5 ISOlat1 -->
-<!ENTITY ouml   "&#246;"> <!-- latin small letter o with diaeresis, U+00F6 ISOlat1 -->
-<!ENTITY divide "&#247;"> <!-- division sign, U+00F7 ISOnum -->
-<!ENTITY oslash "&#248;"> <!-- latin small letter o with stroke, = latin small letter o slash, U+00F8 ISOlat1 -->
-<!ENTITY ugrave "&#249;"> <!-- latin small letter u with grave, U+00F9 ISOlat1 -->
-<!ENTITY uacute "&#250;"> <!-- latin small letter u with acute, U+00FA ISOlat1 -->
-<!ENTITY ucirc  "&#251;"> <!-- latin small letter u with circumflex, U+00FB ISOlat1 -->
-<!ENTITY uuml   "&#252;"> <!-- latin small letter u with diaeresis, U+00FC ISOlat1 -->
-<!ENTITY yacute "&#253;"> <!-- latin small letter y with acute, U+00FD ISOlat1 -->
-<!ENTITY thorn  "&#254;"> <!-- latin small letter thorn, U+00FE ISOlat1 -->
-<!ENTITY yuml   "&#255;"> <!-- latin small letter y with diaeresis, U+00FF ISOlat1 -->
-
-<!-- Latin Extended-B -->
-<!ENTITY fnof     "&#402;"> <!-- latin small f with hook = function                                    = florin, U+0192 ISOtech -->
-
-<!-- Greek -->
-<!ENTITY Alpha    "&#913;"> <!-- greek capital letter alpha, U+0391 -->
-<!ENTITY Beta     "&#914;"> <!-- greek capital letter beta, U+0392 -->
-<!ENTITY Gamma    "&#915;"> <!-- greek capital letter gamma,
-                                    U+0393 ISOgrk3 -->
-<!ENTITY Delta    "&#916;"> <!-- greek capital letter delta,
-                                    U+0394 ISOgrk3 -->
-<!ENTITY Epsilon  "&#917;"> <!-- greek capital letter epsilon, U+0395 -->
-<!ENTITY Zeta     "&#918;"> <!-- greek capital letter zeta, U+0396 -->
-<!ENTITY Eta      "&#919;"> <!-- greek capital letter eta, U+0397 -->
-<!ENTITY Theta    "&#920;"> <!-- greek capital letter theta,
-                                    U+0398 ISOgrk3 -->
-<!ENTITY Iota     "&#921;"> <!-- greek capital letter iota, U+0399 -->
-<!ENTITY Kappa    "&#922;"> <!-- greek capital letter kappa, U+039A -->
-<!ENTITY Lambda   "&#923;"> <!-- greek capital letter lambda,
-                                    U+039B ISOgrk3 -->
-<!ENTITY Mu       "&#924;"> <!-- greek capital letter mu, U+039C -->
-<!ENTITY Nu       "&#925;"> <!-- greek capital letter nu, U+039D -->
-<!ENTITY Xi       "&#926;"> <!-- greek capital letter xi, U+039E ISOgrk3 -->
-<!ENTITY Omicron  "&#927;"> <!-- greek capital letter omicron, U+039F -->
-<!ENTITY Pi       "&#928;"> <!-- greek capital letter pi, U+03A0 ISOgrk3 -->
-<!ENTITY Rho      "&#929;"> <!-- greek capital letter rho, U+03A1 -->
-<!-- there is no Sigmaf, and no U+03A2 character either -->
-<!ENTITY Sigma    "&#931;"> <!-- greek capital letter sigma,
-                                    U+03A3 ISOgrk3 -->
-<!ENTITY Tau      "&#932;"> <!-- greek capital letter tau, U+03A4 -->
-<!ENTITY Upsilon  "&#933;"> <!-- greek capital letter upsilon,
-                                    U+03A5 ISOgrk3 -->
-<!ENTITY Phi      "&#934;"> <!-- greek capital letter phi,
-                                    U+03A6 ISOgrk3 -->
-<!ENTITY Chi      "&#935;"> <!-- greek capital letter chi, U+03A7 -->
-<!ENTITY Psi      "&#936;"> <!-- greek capital letter psi,
-                                    U+03A8 ISOgrk3 -->
-<!ENTITY Omega    "&#937;"> <!-- greek capital letter omega,
-                                    U+03A9 ISOgrk3 -->
-
-<!ENTITY alpha    "&#945;"> <!-- greek small letter alpha,
-                                    U+03B1 ISOgrk3 -->
-<!ENTITY beta     "&#946;"> <!-- greek small letter beta, U+03B2 ISOgrk3 -->
-<!ENTITY gamma    "&#947;"> <!-- greek small letter gamma,
-                                    U+03B3 ISOgrk3 -->
-<!ENTITY delta    "&#948;"> <!-- greek small letter delta,
-                                    U+03B4 ISOgrk3 -->
-<!ENTITY epsilon  "&#949;"> <!-- greek small letter epsilon,
-                                    U+03B5 ISOgrk3 -->
-<!ENTITY zeta     "&#950;"> <!-- greek small letter zeta, U+03B6 ISOgrk3 -->
-<!ENTITY eta      "&#951;"> <!-- greek small letter eta, U+03B7 ISOgrk3 -->
-<!ENTITY theta    "&#952;"> <!-- greek small letter theta,
-                                    U+03B8 ISOgrk3 -->
-<!ENTITY iota     "&#953;"> <!-- greek small letter iota, U+03B9 ISOgrk3 -->
-<!ENTITY kappa    "&#954;"> <!-- greek small letter kappa,
-                                    U+03BA ISOgrk3 -->
-<!ENTITY lambda   "&#955;"> <!-- greek small letter lambda,
-                                    U+03BB ISOgrk3 -->
-<!ENTITY mu       "&#956;"> <!-- greek small letter mu, U+03BC ISOgrk3 -->
-<!ENTITY nu       "&#957;"> <!-- greek small letter nu, U+03BD ISOgrk3 -->
-<!ENTITY xi       "&#958;"> <!-- greek small letter xi, U+03BE ISOgrk3 -->
-<!ENTITY omicron  "&#959;"> <!-- greek small letter omicron, U+03BF NEW -->
-<!ENTITY pi       "&#960;"> <!-- greek small letter pi, U+03C0 ISOgrk3 -->
-<!ENTITY rho      "&#961;"> <!-- greek small letter rho, U+03C1 ISOgrk3 -->
-<!ENTITY sigmaf   "&#962;"> <!-- greek small letter final sigma,
-                                    U+03C2 ISOgrk3 -->
-<!ENTITY sigma    "&#963;"> <!-- greek small letter sigma,
-                                    U+03C3 ISOgrk3 -->
-<!ENTITY tau      "&#964;"> <!-- greek small letter tau, U+03C4 ISOgrk3 -->
-<!ENTITY upsilon  "&#965;"> <!-- greek small letter upsilon,
-                                    U+03C5 ISOgrk3 -->
-<!ENTITY phi      "&#966;"> <!-- greek small letter phi, U+03C6 ISOgrk3 -->
-<!ENTITY chi      "&#967;"> <!-- greek small letter chi, U+03C7 ISOgrk3 -->
-<!ENTITY psi      "&#968;"> <!-- greek small letter psi, U+03C8 ISOgrk3 -->
-<!ENTITY omega    "&#969;"> <!-- greek small letter omega,
-                                    U+03C9 ISOgrk3 -->
-<!ENTITY thetasym "&#977;"> <!-- greek small letter theta symbol,
-                                    U+03D1 NEW -->
-<!ENTITY upsih    "&#978;"> <!-- greek upsilon with hook symbol,
-                                    U+03D2 NEW -->
-<!ENTITY piv      "&#982;"> <!-- greek pi symbol, U+03D6 ISOgrk3 -->
-
-<!-- General Punctuation -->
-<!ENTITY bull     "&#8226;"> <!-- bullet = black small circle,
-                                     U+2022 ISOpub  -->
-<!-- bullet is NOT the same as bullet operator, U+2219 -->
-<!ENTITY hellip   "&#8230;"> <!-- horizontal ellipsis = three dot leader,
-                                     U+2026 ISOpub  -->
-<!ENTITY prime    "&#8242;"> <!-- prime = minutes = feet, U+2032 ISOtech -->
-<!ENTITY Prime    "&#8243;"> <!-- double prime = seconds = inches,
-                                     U+2033 ISOtech -->
-<!ENTITY oline    "&#8254;"> <!-- overline = spacing overscore,
-                                     U+203E NEW -->
-<!ENTITY frasl    "&#8260;"> <!-- fraction slash, U+2044 NEW -->
-
-<!-- Letterlike Symbols -->
-<!ENTITY weierp   "&#8472;"> <!-- script capital P = power set
-                                     = Weierstrass p, U+2118 ISOamso -->
-<!ENTITY image    "&#8465;"> <!-- blackletter capital I = imaginary part,
-                                     U+2111 ISOamso -->
-<!ENTITY real     "&#8476;"> <!-- blackletter capital R = real part symbol,
-                                     U+211C ISOamso -->
-<!ENTITY trade    "&#8482;"> <!-- trade mark sign, U+2122 ISOnum -->
-<!ENTITY alefsym  "&#8501;"> <!-- alef symbol = first transfinite cardinal,
-                                     U+2135 NEW -->
-<!-- alef symbol is NOT the same as hebrew letter alef,
-     U+05D0 although the same glyph could be used to depict both characters -->
-
-<!-- Arrows -->
-<!ENTITY larr     "&#8592;"> <!-- leftwards arrow, U+2190 ISOnum -->
-<!ENTITY uarr     "&#8593;"> <!-- upwards arrow, U+2191 ISOnum-->
-<!ENTITY rarr     "&#8594;"> <!-- rightwards arrow, U+2192 ISOnum -->
-<!ENTITY darr     "&#8595;"> <!-- downwards arrow, U+2193 ISOnum -->
-<!ENTITY harr     "&#8596;"> <!-- left right arrow, U+2194 ISOamsa -->
-<!ENTITY crarr    "&#8629;"> <!-- downwards arrow with corner leftwards
-                                     = carriage return, U+21B5 NEW -->
-<!ENTITY lArr     "&#8656;"> <!-- leftwards double arrow, U+21D0 ISOtech -->
-<!-- ISO 10646 does not say that lArr is the same as the 'is implied by' arrow
-    but also does not have any other character for that function. So ? lArr can
-    be used for 'is implied by' as ISOtech suggests -->
-<!ENTITY uArr     "&#8657;"> <!-- upwards double arrow, U+21D1 ISOamsa -->
-<!ENTITY rArr     "&#8658;"> <!-- rightwards double arrow,
-                                     U+21D2 ISOtech -->
-<!-- ISO 10646 does not say this is the 'implies' character but does not have
-     another character with this function so ?
-     rArr can be used for 'implies' as ISOtech suggests -->
-<!ENTITY dArr     "&#8659;"> <!-- downwards double arrow, U+21D3 ISOamsa -->
-<!ENTITY hArr     "&#8660;"> <!-- left right double arrow,
-                                     U+21D4 ISOamsa -->
-
-<!-- Mathematical Operators -->
-<!ENTITY forall   "&#8704;"> <!-- for all, U+2200 ISOtech -->
-<!ENTITY part     "&#8706;"> <!-- partial differential, U+2202 ISOtech  -->
-<!ENTITY exist    "&#8707;"> <!-- there exists, U+2203 ISOtech -->
-<!ENTITY empty    "&#8709;"> <!-- empty set = null set = diameter,
-                                     U+2205 ISOamso -->
-<!ENTITY nabla    "&#8711;"> <!-- nabla = backward difference,
-                                     U+2207 ISOtech -->
-<!ENTITY isin     "&#8712;"> <!-- element of, U+2208 ISOtech -->
-<!ENTITY notin    "&#8713;"> <!-- not an element of, U+2209 ISOtech -->
-<!ENTITY ni       "&#8715;"> <!-- contains as member, U+220B ISOtech -->
-<!-- should there be a more memorable name than 'ni'? -->
-<!ENTITY prod     "&#8719;"> <!-- n-ary product = product sign,
-                                     U+220F ISOamsb -->
-<!-- prod is NOT the same character as U+03A0 'greek capital letter pi' though
-     the same glyph might be used for both -->
-<!ENTITY sum      "&#8721;"> <!-- n-ary sumation, U+2211 ISOamsb -->
-<!-- sum is NOT the same character as U+03A3 'greek capital letter sigma'
-     though the same glyph might be used for both -->
-<!ENTITY minus    "&#8722;"> <!-- minus sign, U+2212 ISOtech -->
-<!ENTITY lowast   "&#8727;"> <!-- asterisk operator, U+2217 ISOtech -->
-<!ENTITY radic    "&#8730;"> <!-- square root = radical sign,
-                                     U+221A ISOtech -->
-<!ENTITY prop     "&#8733;"> <!-- proportional to, U+221D ISOtech -->
-<!ENTITY infin    "&#8734;"> <!-- infinity, U+221E ISOtech -->
-<!ENTITY ang      "&#8736;"> <!-- angle, U+2220 ISOamso -->
-<!ENTITY and      "&#8743;"> <!-- logical and = wedge, U+2227 ISOtech -->
-<!ENTITY or       "&#8744;"> <!-- logical or = vee, U+2228 ISOtech -->
-<!ENTITY cap      "&#8745;"> <!-- intersection = cap, U+2229 ISOtech -->
-<!ENTITY cup      "&#8746;"> <!-- union = cup, U+222A ISOtech -->
-<!ENTITY int      "&#8747;"> <!-- integral, U+222B ISOtech -->
-<!ENTITY there4   "&#8756;"> <!-- therefore, U+2234 ISOtech -->
-<!ENTITY sim      "&#8764;"> <!-- tilde operator = varies with = similar to,
-                                     U+223C ISOtech -->
-<!-- tilde operator is NOT the same character as the tilde, U+007E,
-     although the same glyph might be used to represent both  -->
-<!ENTITY cong     "&#8773;"> <!-- approximately equal to, U+2245 ISOtech -->
-<!ENTITY asymp    "&#8776;"> <!-- almost equal to = asymptotic to,
-                                     U+2248 ISOamsr -->
-<!ENTITY ne       "&#8800;"> <!-- not equal to, U+2260 ISOtech -->
-<!ENTITY equiv    "&#8801;"> <!-- identical to, U+2261 ISOtech -->
-<!ENTITY le       "&#8804;"> <!-- less-than or equal to, U+2264 ISOtech -->
-<!ENTITY ge       "&#8805;"> <!-- greater-than or equal to,
-                                     U+2265 ISOtech -->
-<!ENTITY sub      "&#8834;"> <!-- subset of, U+2282 ISOtech -->
-<!ENTITY sup      "&#8835;"> <!-- superset of, U+2283 ISOtech -->
-<!-- note that nsup, 'not a superset of, U+2283' is not covered by the Symbol
-     font encoding and is not included. Should it be, for symmetry?
-     It is in ISOamsn  -->
-<!ENTITY nsub     "&#8836;"> <!-- not a subset of, U+2284 ISOamsn -->
-<!ENTITY sube     "&#8838;"> <!-- subset of or equal to, U+2286 ISOtech -->
-<!ENTITY supe     "&#8839;"> <!-- superset of or equal to,
-                                     U+2287 ISOtech -->
-<!ENTITY oplus    "&#8853;"> <!-- circled plus = direct sum,
-                                     U+2295 ISOamsb -->
-<!ENTITY otimes   "&#8855;"> <!-- circled times = vector product,
-                                     U+2297 ISOamsb -->
-<!ENTITY perp     "&#8869;"> <!-- up tack = orthogonal to = perpendicular,
-                                     U+22A5 ISOtech -->
-<!ENTITY sdot     "&#8901;"> <!-- dot operator, U+22C5 ISOamsb -->
-<!-- dot operator is NOT the same character as U+00B7 middle dot -->
-
-<!-- Miscellaneous Technical -->
-<!ENTITY lceil    "&#8968;"> <!-- left ceiling = apl upstile,
-                                     U+2308 ISOamsc  -->
-<!ENTITY rceil    "&#8969;"> <!-- right ceiling, U+2309 ISOamsc  -->
-<!ENTITY lfloor   "&#8970;"> <!-- left floor = apl downstile,
-                                     U+230A ISOamsc  -->
-<!ENTITY rfloor   "&#8971;"> <!-- right floor, U+230B ISOamsc  -->
-<!ENTITY lang     "&#9001;"> <!-- left-pointing angle bracket = bra,
-                                     U+2329 ISOtech -->
-<!-- lang is NOT the same character as U+003C 'less than'
-     or U+2039 'single left-pointing angle quotation mark' -->
-<!ENTITY rang     "&#9002;"> <!-- right-pointing angle bracket = ket,
-                                     U+232A ISOtech -->
-<!-- rang is NOT the same character as U+003E 'greater than'
-     or U+203A 'single right-pointing angle quotation mark' -->
-
-<!-- Geometric Shapes -->
-<!ENTITY loz      "&#9674;"> <!-- lozenge, U+25CA ISOpub -->
-
-<!-- Miscellaneous Symbols -->
-<!ENTITY spades   "&#9824;"> <!-- black spade suit, U+2660 ISOpub -->
-<!-- black here seems to mean filled as opposed to hollow -->
-<!ENTITY clubs    "&#9827;"> <!-- black club suit = shamrock,
-                                     U+2663 ISOpub -->
-<!ENTITY hearts   "&#9829;"> <!-- black heart suit = valentine,
-                                     U+2665 ISOpub -->
-<!ENTITY diams    "&#9830;"> <!-- black diamond suit, U+2666 ISOpub -->
-
-<!-- C0 Controls and Basic Latin -->
-<!ENTITY quot    "&#34;"> <!-- quotation mark = APL quote,
-                                    U+0022 ISOnum -->
-<!ENTITY amp     "&#38;"> <!-- ampersand, U+0026 ISOnum -->
-<!ENTITY lt      "&#60;"> <!-- less-than sign, U+003C ISOnum -->
-<!ENTITY gt      "&#62;"> <!-- greater-than sign, U+003E ISOnum -->
-
-<!-- Latin Extended-A -->
-<!ENTITY OElig   "&#338;"> <!-- latin capital ligature OE,
-                                    U+0152 ISOlat2 -->
-<!ENTITY oelig   "&#339;"> <!-- latin small ligature oe, U+0153 ISOlat2 -->
-<!-- ligature is a misnomer, this is a separate character in some languages -->
-<!ENTITY Scaron  "&#352;"> <!-- latin capital letter S with caron,
-                                    U+0160 ISOlat2 -->
-<!ENTITY scaron  "&#353;"> <!-- latin small letter s with caron,
-                                    U+0161 ISOlat2 -->
-<!ENTITY Yuml    "&#376;"> <!-- latin capital letter Y with diaeresis,
-                                    U+0178 ISOlat2 -->
-
-<!-- Spacing Modifier Letters -->
-<!ENTITY circ    "&#710;"> <!-- modifier letter circumflex accent,
-                                    U+02C6 ISOpub -->
-<!ENTITY tilde   "&#732;"> <!-- small tilde, U+02DC ISOdia -->
-
-<!-- General Punctuation -->
-<!ENTITY ensp    "&#8194;"> <!-- en space, U+2002 ISOpub -->
-<!ENTITY emsp    "&#8195;"> <!-- em space, U+2003 ISOpub -->
-<!ENTITY thinsp  "&#8201;"> <!-- thin space, U+2009 ISOpub -->
-<!ENTITY zwnj    "&#8204;"> <!-- zero width non-joiner,
-                                    U+200C NEW RFC 2070 -->
-<!ENTITY zwj     "&#8205;"> <!-- zero width joiner, U+200D NEW RFC 2070 -->
-<!ENTITY lrm     "&#8206;"> <!-- left-to-right mark, U+200E NEW RFC 2070 -->
-<!ENTITY rlm     "&#8207;"> <!-- right-to-left mark, U+200F NEW RFC 2070 -->
-<!ENTITY ndash   "&#8211;"> <!-- en dash, U+2013 ISOpub -->
-<!ENTITY mdash   "&#8212;"> <!-- em dash, U+2014 ISOpub -->
-<!ENTITY lsquo   "&#8216;"> <!-- left single quotation mark,
-                                    U+2018 ISOnum -->
-<!ENTITY rsquo   "&#8217;"> <!-- right single quotation mark,
-                                    U+2019 ISOnum -->
-<!ENTITY sbquo   "&#8218;"> <!-- single low-9 quotation mark, U+201A NEW -->
-<!ENTITY ldquo   "&#8220;"> <!-- left double quotation mark,
-                                    U+201C ISOnum -->
-<!ENTITY rdquo   "&#8221;"> <!-- right double quotation mark,
-                                    U+201D ISOnum -->
-<!ENTITY bdquo   "&#8222;"> <!-- double low-9 quotation mark, U+201E NEW -->
-<!ENTITY dagger  "&#8224;"> <!-- dagger, U+2020 ISOpub -->
-<!ENTITY Dagger  "&#8225;"> <!-- double dagger, U+2021 ISOpub -->
-<!ENTITY permil  "&#8240;"> <!-- per mille sign, U+2030 ISOtech -->
-<!ENTITY lsaquo  "&#8249;"> <!-- single left-pointing angle quotation mark,
-                                    U+2039 ISO proposed -->
-<!-- lsaquo is proposed but not yet ISO standardized -->
-<!ENTITY rsaquo  "&#8250;"> <!-- single right-pointing angle quotation mark,
-                                    U+203A ISO proposed -->
-<!-- rsaquo is proposed but not yet ISO standardized -->
-<!ENTITY euro   "&#8364;"> <!-- euro sign, U+20AC NEW -->
-
-]>
-'''
-
-class ConvertError(error.FatalError):
-    """ Raise when html to wiki conversion fails """
-    name = "MoinMoin Convert Error"
-    
-
-class visitor(object):
-    def do(self, tree):
-        self.visit_node_list(tree.childNodes)
-
-    def visit_node_list(self, nodelist):
-        for node in nodelist:
-            self.visit(node)
-
-    def visit(self, node):
-        nodeType = node.nodeType
-        if node.nodeType == Node.ELEMENT_NODE:
-            return self.visit_element(node)
-        elif node.nodeType == Node.ATTRIBUTE_NODE:
-            return self.visit_attribute(node)
-        elif node.nodeType == Node.TEXT_NODE:
-            return self.visit_text(node)
-        elif node.nodeType == Node.CDATA_SECTION_NODE:
-            return self.visit_cdata_section(node)
-
-    def visit_element(self, node):
-        if len(node.childNodes):
-            self.visit_node_list(node.childNodes)
-
-    def visit_attribute(self, node):
-        pass
-	
-    def visit_text(self, node):
-        pass
-
-    def visit_cdata_section(self, node):
-        pass
-
-
-class strip_whitespace(visitor):
-
-    def visit_element(self, node):
-        if node.localName == 'p':
-            # XXX: our formatter adds a whitespace at the end of each paragraph
-            if node.hasChildNodes() and node.childNodes[-1].nodeType == Node.TEXT_NODE:
-                data = node.childNodes[-1].data.rstrip('\n ')
-                # Remove it if empty
-                if data == '':
-                    node.removeChild(node.childNodes[-1])
-                else:
-                    node.childNodes[-1].data = data
-            # Remove empty paragraphs
-            if not node.hasChildNodes():
-                node.parentNode.removeChild(node)
-
-        if node.hasChildNodes():
-            self.visit_node_list(node.childNodes)
-
-
-class convert_tree(visitor):
-    white_space = object()
-    new_line = object()
-        
-    def __init__(self, request, pagename):
-        self.request = request
-        self.pagename = pagename
-    
-    def do(self, tree):
-        self.depth = 0
-        self.text = []
-        self.visit(tree.documentElement)
-        self.check_whitespace()
-        return ''.join(self.text)
-
-    def check_whitespace(self):
-        i = 0
-        text = self.text
-        while i < len(text):
-            if text[i] is self.white_space:
-                if i == 0 or i == len(text)-1:
-                    del text[i]
-                elif text[i-1].endswith(" ") or text[i-1].endswith("\n"):
-                    # last char of previous element is whitespace
-                    del text[i]
-                elif (text[i+1] is self.white_space or
-                      # next element is white_space
-                      text[i+1] is self.new_line):
-                      # or new_line
-                    del text[i]
-                elif text[i+1].startswith(" ") or text[i+1].startswith("\n"):
-                    # first char of next element is whitespace
-                    del text[i]
-                else:
-                    text[i] = " "
-                    i += 1
-            elif text[i] is self.new_line:
-                if i == 0:
-                    del text[i]
-                elif i == len(text) - 1:
-                    text[i] = "\n"
-                    i += 1
-                elif text[i-1].endswith("\n") or (
-                      isinstance(text[i+1], str) and text[i+1].startswith("\n")):
-                    del text[i]
-                else:
-                    text[i] = "\n"
-                    i += 1
-            else:
-                i += 1
-
-    def visit_text(self, node):
-        self.text.append(node.data)
-
-    def visit_element(self, node):
-        name = node.localName
-        if name is None: # not sure this can happen here (DOM comment node), but just for the case
-            return
-        func = getattr(self, "process_%s" % name,  None)
-        if func:
-            func(node)
-        else:
-            self.process_inline(node)
-
-    def visit_node_list_element_only(self, nodelist):
-        for node in nodelist:
-            if node.nodeType == Node.ELEMENT_NODE:
-                self.visit_element(node)
-
-    def node_list_text_only(self, nodelist):
-        result = []
-        for node in nodelist:
-            if node.nodeType == Node.TEXT_NODE:
-                result.append(node.data)
-            else:
-                result.extend(self.node_list_text_only(node.childNodes))
-        return "".join(result)
-
-    def process_page(self, node):
-        for i in node.childNodes:
-            if i.nodeType == Node.ELEMENT_NODE:
-                self.visit_element(i)
-            elif i.nodeType == Node.TEXT_NODE: # if this is missing, all std text under a headline is dropped!
-                txt = i.data.strip() # IMPORTANT: don't leave this unstripped or there will be wrong blanks
-                if txt:
-                    self.text.append(txt)
-            #we use <pre class="comment"> now, so this is currently unused:
-            #elif i.nodeType == Node.COMMENT_NODE:
-            #    self.text.append(i.data)
-            #    self.text.append("\n")
-
-    def process_br(self, node):
-            self.text.append(self.new_line) # without this, std multi-line text below some heading misses a whitespace
-                                            # when it gets merged to float text, like word word wordword word word
-
-    def process_heading(self, node):
-        text = self.node_list_text_only(node.childNodes).strip()
-        if text:
-            depth = int(node.localName[1]) - 1
-            hstr = "=" * depth
-            self.text.append(self.new_line)
-            self.text.append("%s %s %s" % (hstr, text.replace("\n", " "), hstr))
-            self.text.append(self.new_line)
-    
-    process_h1 = process_heading
-    process_h2 = process_heading
-    process_h3 = process_heading
-    process_h4 = process_heading
-    process_h5 = process_heading
-    process_h6 = process_heading
-
-    def _get_list_item_markup(self, list, listitem):
-        before = ""
-        #indent = str(self.depth) * self.depth # nice for debugging :)
-        indent = " " * self.depth
-        markup = ""
-        name = list.localName
-        if name == 'ol':
-            class_ = listitem.getAttribute("class")
-            if class_ == "gap":
-                before = "\n"
-            if list.hasAttribute("type"):
-                type = list.getAttribute("type")
-            else:
-                type = "1"
-            markup = "%s. " % type
-        elif name == 'ul':
-            class_ = listitem.getAttribute("class")
-            if class_ == "gap":
-                before = "\n"
-            style = listitem.getAttribute("style")
-            if re.match(u"list-style-type:\s*none", style, re.I):
-                markup = ". "
-            else:
-                markup = "* "
-        elif name == 'dl':
-            markup = ":: "
-        else:
-            raise ConvertError("Illegal list type %s" % name)
-        return before, indent, markup
-
-    def process_dl(self, node):
-        self.depth += 1
-        markup = ":: " # can there be a dl dd without dt?
-        for i in node.childNodes:
-            if i.nodeType == Node.ELEMENT_NODE:
-                name = i.localName
-                if name == 'dt':
-                    before, indent, markup = self._get_list_item_markup(node, i)
-                    self.text.append(before+indent)
-                    text = self.node_list_text_only(i.childNodes)
-                    self.text.append(text.replace("\n", " "))
-                elif name == 'dd':
-                    self.text.append(markup)
-                    self.process_list_item(i, indent)
-                else:
-                    raise ConvertError("Illegal list element %s" % i.localName)
-        self.depth -= 1
-        if self.depth == 0:
-            self.text.append(self.new_line)
-
-    def process_list(self, node):
-        self.depth += 1
-        for i in node.childNodes:
-            if i.nodeType == Node.ELEMENT_NODE:
-                name = i.localName
-                if name == 'li':
-                    before, indent, markup = self._get_list_item_markup(node, i)
-                    self.text.append(before+indent+markup)
-                    self.process_list_item(i, indent)
-                elif name in ('ol', 'ul',):
-                    self.process_list(i)
-                elif name == 'dl':
-                    self.process_dl(i)
-                else:
-                    raise ConvertError("Illegal list element %s" % i.localName)
-        self.depth -= 1
-        if self.depth == 0:
-            self.text.append(self.new_line)
-
-    process_ul = process_list
-    process_ol = process_list
-
-    def empty_paragraph_queue(self, nodelist, indent, need_indent):
-        if need_indent:
-            self.text.append(indent)
-        for i in nodelist:
-            if i.nodeType == Node.ELEMENT_NODE:
-                self.process_inline(i)
-            elif i.nodeType == Node.TEXT_NODE:
-                self.text.append(i.data.strip('\n').replace('\n', ' '))
-        self.text.append(self.new_line)
-        del nodelist[:]
-
-    def process_list_item(self, node, indent):
-        found = False
-        need_indent = False
-        pending = []
-        for i in node.childNodes:
-            name = i.localName
-
-            if name in ('p', 'pre', 'ol', 'ul', 'dl', 'table',) and pending:
-                self.empty_paragraph_queue(pending, indent, need_indent)
-                need_indent = True
-                
-            if name == 'p':
-                if need_indent:
-                    self.text.append(indent)
-                self.process_paragraph_item(i)
-                self.text.append(self.new_line)
-                found = True
-            elif name == 'pre':
-                if need_indent:
-                    self.text.append(indent)
-                self.process_preformatted_item(i)
-                found = True
-            elif name in ('ol', 'ul',):
-                self.process_list(i)
-                found = True
-            elif name == 'dl':
-                self.process_dl(i)
-                found = True
-            elif name == 'table':
-                if need_indent:
-                    self.text.append(indent)
-                self.process_table(i)
-                found = True
-            else:
-                pending.append(i)
-
-            if found:
-                need_indent = True
-
-        if pending:
-            self.empty_paragraph_queue(pending, indent, need_indent)
-
-    def process_blockquote(self, node):
-        # XXX this does not really work. e.g.:
-        # <bq>aaaaaa
-        # <hr---------->
-        # <bq>bbbbbb
-        self.depth += 1
-        for i in node.childNodes:
-            if i.nodeType == Node.ELEMENT_NODE:
-                name = i.localName
-                if name == 'p':
-                    self.text.append(self.new_line)
-                    self.text.append(" " * self.depth)
-                    self.process_p(i)
-                elif name == 'pre':
-                    self.text.append(self.new_line)
-                    self.text.append(" " * self.depth)
-                    self.process_pre(i)
-                elif name in ('h1', 'h2', 'h3', 'h4', 'h5', 'h6',):
-                    self.process_heading(i)
-                elif name in ('ol', 'ul',):
-                    self.process_list(i)
-                elif name == 'dl':
-                    self.process_dl(i)
-                elif name == 'img':
-                    self.process_img(i)
-                elif name == 'div':
-                    self.visit_node_list_element_only(i.childNodes)
-                elif name == 'blockquote':
-                    self.process_blockquote(i)
-                elif name == 'hr':
-                    self.process_hr(i)
-                elif name == 'br':
-                    self.process_br(i)
-                else:
-                    raise ConvertError("process_blockquote: Don't support %s element" % name)
-        self.depth -= 1
-
-    def process_inline(self, node):
-        if node.nodeType == Node.TEXT_NODE:
-            self.text.append(node.data.strip('\n').replace('\n',' '))
-            return
-
-        name = node.localName # can be None for DOM Comment nodes
-        if name is None:
-            return
-
-        if name in ('h1', 'h2', 'h3', 'h4', 'h5', 'h6',): # headers are not allowed here (e.g. inside a ul li),
-            text = self.node_list_text_only(node.childNodes).strip() # but can be inserted via the editor
-            self.text.append(text)                          # so we just drop the header markup and keep the text
-            return
-        
-        func = getattr(self, "process_%s" % name,  None)
-        if func:
-            func(node)
-            return
-
-        command_close = None
-        if name in ('em', 'i',):
-            command = "''"
-        elif name in ('strong', 'b',):
-            command = "'''"
-        elif name == 'u':
-            command = "__"
-        elif name == 'big':
-            command = "~+"
-            command_close = "+~"
-        elif name == 'small':
-            command = "~-"
-            command_close = "-~"
-        elif name == 'strike':
-            command = "--("
-            command_close = ")--"
-        elif name == 'sub':
-            command = ",,"
-        elif name == 'sup':
-            command = "^"
-        elif name == 'font':
-            command = "" # just throw away font settings
-        else:
-            raise ConvertError("process_inline: Don't support %s element" % name)
-        
-        self.text.append(command)
-        for i in node.childNodes:
-            if i.nodeType == Node.ELEMENT_NODE:
-                self.process_inline(i)
-            elif i.nodeType == Node.TEXT_NODE:
-                self.text.append(i.data.strip('\n').replace('\n',' '))
-        if command_close:
-            command = command_close
-        self.text.append(command)
-
-    def process_span(self, node):
-        # ignore span tags - just descend
-        for i in node.childNodes:
-            self.process_inline(i)
-
-    def process_div(self, node):
-        # ignore div tags - just descend
-        for i in node.childNodes:
-            self.visit_element(i)
-
-    def process_tt(self, node):
-        text = self.node_list_text_only(node.childNodes).replace("\n", " ")
-        if node.getAttribute("css") == "backtick":
-            self.text.append("`%s`" % text)
-        else:
-            self.text.append("{{{%s}}}" % text)
-
-    def process_hr(self, node):
-        if node.hasAttribute("class"):
-            class_ = node.getAttribute("class")
-        else:
-            class_ = "hr0"
-        if class_.startswith("hr") and class_[2] in "123456":
-            length = int(class_[2]) + 4
-        else:
-            length = 4
-        self.text.extend([self.new_line, "-" * length, self.new_line])
-
-    def process_p(self, node):
-        self.process_paragraph_item(node)
-        self.text.append("\n\n") # do not use self.new_line here!
-
-    def process_paragraph_item(self, node):
-        for i in node.childNodes:
-            if i.nodeType == Node.ELEMENT_NODE:
-                self.process_inline(i)
-            elif i.nodeType == Node.TEXT_NODE:
-                self.text.append(i.data.strip('\n').replace('\n', ' '))
-
-    def process_pre(self, node):
-        self.process_preformatted_item(node)
-        self.text.append(self.new_line)
-
-    def process_preformatted_item(self, node):
-        if node.hasAttribute("class"):
-            class_ = node.getAttribute("class")
-        else:
-            class_ = None
-        if class_ == "comment": # we currently use this for stuff like ## or #acl
-            for i in node.childNodes:
-                if i.nodeType == Node.TEXT_NODE:
-                    self.text.append(i.data)
-                    #print "'%s'" % i.data
-                elif i.localName == 'br':
-                    self.text.append(self.new_line)
-                else:
-                    pass
-                    #print i.localName
-        else:
-            self.text.extend(["{{{", self.new_line])
-            for i in node.childNodes:
-                if i.nodeType == Node.TEXT_NODE:
-                    self.text.append(i.data)
-                    #print "'%s'" % i.data
-                elif i.localName == 'br':
-                    self.text.append(self.new_line)
-                else:
-                    pass
-                    #print i.localName
-            self.text.extend(["}}}", self.new_line])
-
-    _alignment = {"left" : "(",
-                  "center" : ":",
-                  "right" : ")",
-                  "top" : "^",
-                  "bottom" : "v"}
-
-    def _check_length(self, value):
-        try:
-            int(value)
-            return value + 'px'
-        except ValueError:
-            return value
-
-    def _table_style(self, node):
-        result = []
-        if node.hasAttribute("bgcolor"):
-            value = node.getAttribute("bgcolor")
-            match = re.match(r"rgb\((\d+),\s*(\d+),\s*(\d+)\)", value)
-            if match:
-                result.append('tablebgcolor="#%X%X%X"' %
-                              (int(match.group(1)),
-                               int(match.group(2)),
-                               int(match.group(3))))
-            else:
-                result.append('tablebgcolor="%s"' % value)
-        if node.hasAttribute("width"):
-            value = node.getAttribute("width")
-            result.append('tablewidth="%s"' % self._check_length(value))
-        if node.hasAttribute("height"):
-            value = node.getAttribute("height")
-            result.append('tableheight="%s"' % self._check_length(value))
-        if node.hasAttribute("align"):
-            value = node.getAttribute("align")
-            result.append('tablealign="%s"' % value)
-        if node.hasAttribute("style"):
-            result.append('tablestyle="%s"' % node.getAttribute("style"))
-        if node.hasAttribute("class"):
-            result.append('tableclass="%s"' % node.getAttribute("class"))
-        return " ".join(result).strip()
-
-    def _row_style(self, node):
-        result = []
-        if node.hasAttribute("bgcolor"):
-            value = node.getAttribute("bgcolor")
-            match = re.match(r"rgb\((\d+),\s*(\d+),\s*(\d+)\)", value)
-            if match:
-                result.append('rowbgcolor="#%X%X%X"' %
-                              (int(match.group(1)),
-                               int(match.group(2)),
-                               int(match.group(3))))
-            else:
-                result.append('rowbgcolor="%s"' % value)
-        if node.hasAttribute("style"):
-            result.append('rowstyle="%s"' % node.getAttribute("style"))
-        return " ".join(result).strip()
-
-    def _cell_style(self, node):
-        if node.hasAttribute("rowspan"):
-            rowspan = ("|%s" % node.getAttribute("rowspan"))
-        else:
-            rowspan = ""
-
-        if node.hasAttribute("colspan"):
-            colspan = int(node.getAttribute("colspan"))
-        else:
-            colspan = 1
-
-        spanning = rowspan or colspan > 1
-        
-        align = ""
-        result = []
-        if  node.hasAttribute("bgcolor"):
-            value = node.getAttribute("bgcolor")
-            match = re.match(r"rgb\((\d+),\s*(\d+),\s*(\d+)\)", value)
-            if match:
-                result.append("#%X%X%X" % (int(match.group(1)),
-                                           int(match.group(2)),
-                                           int(match.group(3))))
-            else:
-                result.append('bgcolor="%s"' % value)
-        if node.hasAttribute("align"):
-            value = node.getAttribute("align")
-            if not spanning or value != "center":
-                # ignore "center" in spanning cells
-                align += self._alignment.get(value, "")
-        if node.hasAttribute("valign"):
-            value = node.getAttribute("valign")
-            if not spanning or value != "center":
-                # ignore "center" in spanning cells
-                align += self._alignment.get(value, "")
-        if node.hasAttribute("width"):
-            value = node.getAttribute("width")
-            if value[-1] == "%":
-                align += value
-            else:
-                result.append('width="%s"' % self._check_length(value))
-        if node.hasAttribute("height"):
-            value = node.getAttribute("height")
-            result.append('height="%s"' % self._check_length(value))
-        if node.hasAttribute("class"):
-            result.append('class="%s"' % node.getAttribute("class"))
-        if node.hasAttribute("id"):
-            result.append('id="%s"' % node.getAttribute("id"))
-        if node.hasAttribute("style"):
-            result.append('style="%s"' % node.getAttribute("style"))
-                
-        if align:
-            result[0:0] = "%s" % align
-        result.append(rowspan)
-        return " ".join(result).strip()
-
-    def process_table(self, node, style=""):
-        self.text.append(self.new_line)
-        self.new_table = True
-        style += self._table_style(node)
-        for i in node.childNodes:
-            if i.nodeType == Node.ELEMENT_NODE:
-                name = i.localName
-                if name == 'tr':
-                    self.process_table_record(i, style)
-                    style = ""
-                elif name in ('thead', 'tbody', 'tfoot'):
-                    self.process_table(i, style)
-                elif name == 'caption':
-                    self.process_caption(node, i, style)
-                    style = ''
-                else:
-                    raise ConvertError("process_table: Don't support %s element" % name)
-            #else:
-            #    raise ConvertError("Unexpected node: %r" % i)
-        self.text.append(self.new_line)
-
-    def process_caption(self, table, node, style=""):
-        # get first row
-        for i in table.childNodes:
-            if i.localName in ('thead', 'tbody', 'tfoot'): # XXX is this correct?
-            #if i.localName == 'tbody': (old version)
-                for i in i.childNodes:
-                    if i.localName == 'tr':
-                        break
-                break
-            elif i.localName == 'tr':
-                break
-        # count columns
-        if i.localName == 'tr':
-            colspan = 0
-            for td in i.childNodes:
-                if not td.nodeType == Node.ELEMENT_NODE:
-                    continue
-                span = td.getAttribute('colspan')
-                try:
-                    colspan += int(span)
-                except ValueError:
-                    colspan += 1
-        else:
-            colspan = 1
-        text = self.node_list_text_only(node.childNodes).replace('\n', ' ').strip()
-        if text:
-            self.text.extend(["%s'''%s%s'''||" % ('||' * colspan, style, text), self.new_line])
-
-    def process_table_data(self, node, style=""):
-        if node.hasAttribute("colspan"):
-            colspan = int(node.getAttribute("colspan"))
-        else:
-            colspan = 1
-        self.text.append("||" * colspan)
-
-        style += self._cell_style(node)
-        if style:
-            self.text.append("<%s>" % style)
-
-        found = False
-        for i in node.childNodes:
-            name = i.localName
-            if name == 'p':
-                self.process_paragraph_item(i)
-                self.text.append(self.white_space)
-                found = True
-        if not found:
-            for i in node.childNodes:
-                if i.nodeType == Node.ELEMENT_NODE:
-                    self.process_inline(i)
-                    found = True
-                elif i.nodeType == Node.TEXT_NODE:
-                    data = i.data.strip('\n').replace('\n',' ')
-                    if data:
-                        found = True
-                        self.text.append(data)
-        if not found:
-            self.text.append(" ")
-
-    def process_table_record(self, node, style=""):
-        if not self.new_table:
-            self.text.append(" " * self.depth)
-        else:
-            self.new_table = False
-        style += self._row_style(node)
-        for i in node.childNodes:
-            if i.nodeType == Node.ELEMENT_NODE:
-                name = i.localName
-                if name == 'td':
-                    self.process_table_data(i, style=style)
-                    style = ""
-                else:
-                    raise ConvertError("process_table_record: Don't support %s element" % name)
-        self.text.extend(["||", self.new_line])
-
-    def process_a(self, node):
-        scriptname = self.request.getScriptname()
-        if scriptname == "":
-            scriptname = "/"
-        # can either be a link (with href) or an anchor (with e.g. id)
-        href = node.attributes.get("href", None)
-        if href:
-            href = wikiutil.url_unquote(href.nodeValue)
-        id = node.attributes.get("id", None)
-        if id:
-            id = id.nodeValue
-        
-        if href:
-            title = class_ = interwikiname = None
-
-            if node.attributes.has_key("title"):
-                title = node.attributes.get("title").nodeValue
-            if node.attributes.has_key("class"):
-                class_ = node.attributes.get("class").nodeValue
-
-            text = self.node_list_text_only(node.childNodes)
-            text = text.replace("\n", " ").lstrip()
-
-             # interwiki link
-            if class_ == "interwiki":
-                wikitag, wikiurl, wikitail, err = wikiutil.resolve_wiki(
-                    self.request, title + ":")
-                if not err and href.startswith(wikiurl):
-                    pagename = href[len(wikiurl):].lstrip('/')
-                    interwikiname = "%s:%s" % (wikitag, pagename)
-                else: 
-                    raise ConvertError("Invalid InterWiki link: '%s'" % href)
-            elif class_ == "badinterwiki" and title:
-                pagename = href
-                interwikiname = "%s:%s" % (title, href)
-            if interwikiname and pagename == text: 
-                self.text.append("%s" % interwikiname)
-                return
-            elif title == 'Self':
-                self.text.append("[:%s:%s]" % (href, text))
-                return
-            elif interwikiname:
-                self.text.append("[wiki:%s %s]" % (interwikiname, text))
-                return
-            
-            # fix links generated by a broken copy & paste of gecko based browsers
-            brokenness = '../../../..'
-            if href.startswith(brokenness):
-                href = href[len(brokenness):] # just strip it away!
-            # TODO: IE pastes complete http://server/Page/SubPage as href and as text, too
-
-            # Attachments
-            if title and title.startswith("attachment:"):
-                url = wikiutil.url_unquote(title[len("attachment:"):])
-                if url != text:
-                    self.text.append("[%s %s]" % (title, text))
-                else:
-                    self.text.extend([self.white_space, title, self.white_space])
-            # wiki link
-            elif href.startswith(scriptname):
-                pagename = href[len(scriptname):].replace('_', ' ')
-                pagename = pagename.lstrip('/')    # XXX temp fix for generated pagenames starting with /
-                if text == pagename:
-                    self.text.append(wikiutil.pagelinkmarkup(pagename))
-                # relative link /SubPage
-                elif href.endswith(text):
-                    if pagename.startswith(self.pagename): # is this a subpage of us?
-                        self.text.append(wikiutil.pagelinkmarkup(pagename[len(self.pagename):]))
-                    else:
-                        self.text.append(wikiutil.pagelinkmarkup(pagename))
-                # relative link ../
-                elif href.endswith(text.lstrip("..").lstrip("/")):
-                    self.text.append(wikiutil.pagelinkmarkup(text))
-                # labeled link
-                else:
-                    self.text.append("[:%s:%s]" % (pagename, text))
-            # mailto link
-            elif href.startswith("mailto:"):
-                if href[len("mailto:"):] == text:
-                    self.text.extend([self.white_space, text, self.white_space])
-                else:
-                    self.text.append("[%s %s]" % (href, text))
-            # simple link
-            elif href.replace(" ", "%20") == text:
-                self.text.append("%s" % text)
-            # imagelink
-            elif text == "" and wikiutil.isPicture(href):
-                self.text.append("[%s]" % href)
-            # labeled link
-            else:
-                href = href.replace(" ", "%20")
-                self.text.append("[%s %s]" % (href, text))
-        elif id:
-            pass # we dont support anchors yet
-
-    def process_img(self, node):
-        src = None
-        if node.attributes.has_key("src"):
-            src = wikiutil.url_unquote(node.attributes.get("src").nodeValue)
-        title = None
-        if node.attributes.has_key("title"):
-            title = node.attributes.get("title").nodeValue
-        alt = None
-        if node.attributes.has_key("alt"):
-            alt = node.attributes.get("alt").nodeValue
-
-        # Attachment image
-        if (title and title.startswith("attachment:") and
-            wikiutil.isPicture(wikiutil.url_unquote(title[len("attachment:"):]))):
-            self.text.extend([self.white_space,
-                              wikiutil.url_unquote(title),
-                              self.white_space])
-        # Drawing image
-        elif title and title.startswith("drawing:"):
-            self.text.extend([self.white_space,
-                              wikiutil.url_unquote(title),
-                              self.white_space])
-        # Smiley
-        elif src and (self.request.cfg.url_prefix in src or '../' in src) and "img/" in src: # XXX this is dirty!
-            filename = src.split("/")[-1]
-            for name, data in config.smileys.iteritems():
-                if data[3] == filename:
-                    self.text.extend([self.white_space, name, self.white_space])
-                    return
-                else:
-                    pass #print name, data, filename, alt
-            raise ConvertError("Unknown smiley icon '%s'" % filename)
-        # Image URL
-        elif src and src.startswith("http") and wikiutil.isPicture(src): # matches http: and https: !
-            self.text.extend([self.white_space, src, self.white_space])
-        else:
-            raise ConvertError("Strange image src: '%s'" % src)
-
-
-def parse(request, text):
-    text = u'<?xml version="1.0"?>%s%s' % (dtd, text)
-    text = text.encode(config.charset)
-    try:
-        return xml.dom.minidom.parseString(text)
-    except xml.parsers.expat.ExpatError, msg:
-        # this sometimes crashes when it should not, so save the stuff to analyze it:
-        logname = os.path.join(request.cfg.data_dir, "expaterror.log")
-        f = file(logname, "w")
-        f.write(text)
-        f.write("\n" + "-"*80 + "\n" + str(msg))
-        f.close()
-        raise ConvertError('ExpatError: %s (see dump in %s)' % (msg, logname))
-
-def convert(request, pagename, text):
-    text = u"<page>%s</page>" % text
-    tree = parse(request, text)
-    strip_whitespace().do(tree)
-    text = convert_tree(request, pagename).do(tree)
-    text = '\n'.join([s.rstrip() for s in text.splitlines()] + ['']) # remove trailing blanks
-    return text
-
--- a/MoinMoin/formatter/__init__.py	Tue May 16 11:44:24 2006 +1200
+++ b/MoinMoin/formatter/__init__.py	Wed May 17 09:27:26 2006 +1200
@@ -1,13 +1,375 @@
 # -*- coding: iso-8859-1 -*-
 """
-    MoinMoin - Formatter Package
+    MoinMoin - Formatter Package and FormatterBase
 
     See "base.py" for the formatter interface.
 
-    @copyright: 2000 by Jürgen Hermann <jh@web.de>
+    @copyright: 2000-2004 by Jürgen Hermann <jh@web.de>
     @license: GNU GPL, see COPYING for details.
 """
 from MoinMoin.util import pysupport
 
 modules = pysupport.getPackageModules(__file__)
 
+from MoinMoin import wikiutil
+import re, types
+
+class FormatterBase:
+    """ This defines the output interface used all over the rest of the code.
+
+        Note that no other means should be used to generate _content_ output,
+        while navigational elements (HTML page header/footer) and the like
+        can be printed directly without violating output abstraction.
+    """
+
+    hardspace = ' '
+
+    def __init__(self, request, **kw):
+        self.request = request
+        self._ = request.getText
+
+        self._store_pagelinks = kw.get('store_pagelinks', 0)
+        self._terse = kw.get('terse', 0)
+        self.pagelinks = []
+        self.in_p = 0
+        self.in_pre = 0
+        self._highlight_re = None
+        self._base_depth = 0
+
+    def set_highlight_re(self, hi_re=None):
+        if type(hi_re) in [types.StringType, types.UnicodeType]:
+            try:
+                self._highlight_re = re.compile(hi_re, re.U + re.IGNORECASE)
+            except re.error:
+                hi_re = re.escape(hi_re)
+                self._highlight_re = re.compile(hi_re, re.U + re.IGNORECASE)
+        else:
+            self._highlight_re = hi_re
+
+    def lang(self, on, lang_name):
+        return ""
+
+    def setPage(self, page):
+        self.page = page
+
+    def sysmsg(self, on, **kw):
+        """ Emit a system message (embed it into the page).
+
+            Normally used to indicate disabled options, or invalid markup.
+        """
+        return ""
+
+    # Document Level #####################################################
+    
+    def startDocument(self, pagename):
+        return ""
+
+    def endDocument(self):
+        return ""
+
+    def startContent(self, content_id="content", **kw):
+        return ""
+
+    def endContent(self):
+        return ""
+
+    # Links ##############################################################
+    
+    def pagelink(self, on, pagename='', page=None, **kw):
+        """ make a link to page <pagename>. Instead of supplying a pagename,
+            it is also possible to give a live Page object, then page.page_name
+            will be used.
+        """
+        if not self._store_pagelinks or not on or kw.get('generated'): 
+            return ''
+        if not pagename and page:
+            pagename = page.page_name
+        pagename = self.request.normalizePagename(pagename)
+        if pagename and pagename not in self.pagelinks:
+            self.pagelinks.append(pagename)
+
+    def interwikilink(self, on, interwiki='', pagename='', **kw):
+        """ calls pagelink() for internal interwikilinks
+            to make sure they get counted for self.pagelinks.
+            IMPORTANT: on and off must be called with same parameters, see
+                       also the text_html formatter.
+        """
+        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, '%s:%s' % (interwiki, pagename))
+        if wikitag == 'Self' or wikitag == self.request.cfg.interwikiname:
+            if wikitail.find('#') > -1:
+                wikitail, kw['anchor'] = wikitail.split('#', 1)
+                wikitail = wikiutil.url_unquote(wikitail)
+            return self.pagelink(on, wikitail, **kw)
+        return ''
+            
+    def url(self, on, url=None, css=None, **kw):
+        raise NotImplementedError
+
+    # Attachments ######################################################
+
+    def attachment_link(self, url, text, **kw):
+        raise NotImplementedError
+    def attachment_image(self, url, **kw):
+        raise NotImplementedError
+    def attachment_drawing(self, url, text, **kw):
+        raise NotImplementedError
+
+    def attachment_inlined(self, url, text, **kw):
+        from MoinMoin.action import AttachFile
+        import os
+        _ = self.request.getText
+        pagename, filename = AttachFile.absoluteName(url, self.page.page_name)
+        fname = wikiutil.taintfilename(filename)
+        fpath = AttachFile.getFilename(self.request, pagename, fname)
+        base, ext = os.path.splitext(filename)
+        Parser = wikiutil.getParserForExtension(self.request.cfg, ext)
+        if Parser is not None:
+            try:
+                content = file(fpath, 'r').read()
+                # Try to decode text. It might return junk, but we don't
+                # have enough information with attachments.
+                content = wikiutil.decodeUnknownInput(content)
+                colorizer = Parser(content, self.request)
+                colorizer.format(self)
+            except IOError:
+                pass
+
+        return self.attachment_link(url, text)
+
+    def anchordef(self, name):
+        return ""
+
+    def line_anchordef(self, lineno):
+        return ""
+
+    def anchorlink(self, on, name='', **kw):
+        return ""
+
+    def line_anchorlink(self, on, lineno=0):
+        return ""
+
+    def image(self, src=None, **kw):
+        """An inline image.
+
+        Extra keyword arguments are according to the HTML <img> tag attributes.
+        In particular an 'alt' or 'title' argument should give a description
+        of the image.
+        """
+        title = src
+        for titleattr in ('title', 'html__title', 'alt', 'html__alt'):
+            if kw.has_key(titleattr):
+                title = kw[titleattr]
+                break
+        if title:
+            return '[Image:%s]' % title
+        return '[Image]'
+
+    def smiley(self, text):
+        return text
+
+    def nowikiword(self, text):
+        return self.text(text)
+
+    # Text and Text Attributes ########################################### 
+    
+    def text(self, text, **kw):
+        if not self._highlight_re:
+            return self._text(text)
+            
+        result = []
+        lastpos = 0
+        match = self._highlight_re.search(text)
+        while match and lastpos < len(text):
+            # add the match we found
+            result.append(self._text(text[lastpos:match.start()]))
+            result.append(self.highlight(1))
+            result.append(self._text(match.group(0)))
+            result.append(self.highlight(0))
+
+            # search for the next one
+            lastpos = match.end() + (match.end() == lastpos)
+            match = self._highlight_re.search(text, lastpos)
+
+        result.append(self._text(text[lastpos:]))
+        return ''.join(result)
+
+    def _text(self, text):
+        raise NotImplementedError
+
+    def strong(self, on, **kw):
+        raise NotImplementedError
+
+    def emphasis(self, on, **kw):
+        raise NotImplementedError
+
+    def underline(self, on, **kw):
+        raise NotImplementedError
+
+    def highlight(self, on, **kw):
+        raise NotImplementedError
+
+    def sup(self, on, **kw):
+        raise NotImplementedError
+
+    def sub(self, on, **kw):
+        raise NotImplementedError
+
+    def strike(self, on, **kw):
+        raise NotImplementedError
+
+    def code(self, on, **kw):
+        raise NotImplementedError
+
+    def preformatted(self, on, **kw):
+        self.in_pre = on != 0
+
+    def small(self, on, **kw):
+        raise NotImplementedError
+
+    def big(self, on, **kw):
+        raise NotImplementedError
+
+    # special markup for syntax highlighting #############################
+
+    def code_area(self, on, code_id, **kw):
+        raise NotImplementedError
+
+    def code_line(self, on):
+        raise NotImplementedError
+
+    def code_token(self, tok_text, tok_type):
+        raise NotImplementedError
+
+    # Paragraphs, Lines, Rules ###########################################
+
+    def linebreak(self, preformatted=1):
+        raise NotImplementedError
+
+    def paragraph(self, on, **kw):
+        self.in_p = on != 0
+
+    def rule(self, size=0, **kw):
+        raise NotImplementedError
+
+    def icon(self, type):
+        return type
+
+    # Lists ##############################################################
+
+    def number_list(self, on, type=None, start=None, **kw):
+        raise NotImplementedError
+
+    def bullet_list(self, on, **kw):
+        raise NotImplementedError
+
+    def listitem(self, on, **kw):
+        raise NotImplementedError
+
+    def definition_list(self, on, **kw):
+        raise NotImplementedError
+
+    def definition_term(self, on, compact=0, **kw):
+        raise NotImplementedError
+
+    def definition_desc(self, on, **kw):
+        raise NotImplementedError
+
+    def heading(self, on, depth, **kw):
+        raise NotImplementedError
+
+    # Tables #############################################################
+    
+    def table(self, on, attrs={}, **kw):
+        raise NotImplementedError
+
+    def table_row(self, on, attrs={}, **kw):
+        raise NotImplementedError
+
+    def table_cell(self, on, attrs={}, **kw):
+        raise NotImplementedError
+
+    # Dynamic stuff / Plugins ############################################
+    
+    def macro(self, macro_obj, name, args):
+        # call the macro
+        return macro_obj.execute(name, args)    
+
+    def _get_bang_args(self, line):
+        if line[:2] == '#!':
+            try:
+                name, args = line[2:].split(None, 1)
+            except ValueError:
+                return ''
+            else:
+                return args
+        return None
+
+    def parser(self, parser_name, lines):
+        """ parser_name MUST be valid!
+            writes out the result instead of returning it!
+        """
+        mt = wikiutil.MimeType(parser_name)
+        for module_name in mt.module_name():
+            try:
+                parser = wikiutil.importPlugin(self.request.cfg, "parser", module_name, "Parser")
+                break
+            except PluginMissingError:
+                pass
+        else:
+            raise "Parser not found" # XXX what now?
+        args = self._get_bang_args(lines[0])
+        if args is not None:
+            lines = lines[1:]
+        p = parser('\n'.join(lines), self.request, format_args=args)
+        p.format(self)
+        del p
+        return ''
+
+    def dynamic_content(self, parser, callback, arg_list=[], arg_dict={},
+                        returns_content=1):
+        content = parser[callback](*arg_list, **arg_dict)
+        if returns_content:
+            return content
+        else:
+            return ''
+
+    # Other ##############################################################
+    
+    def div(self, on, **kw):
+        """ open/close a blocklevel division """
+        return ""
+    
+    def span(self, on, **kw):
+        """ open/close a inline span """
+        return ""
+    
+    def rawHTML(self, markup):
+        """ This allows emitting pre-formatted HTML markup, and should be
+            used wisely (i.e. very seldom).
+
+            Using this event while generating content results in unwanted
+            effects, like loss of markup or insertion of CDATA sections
+            when output goes to XML formats.
+        """
+
+        import formatter, htmllib
+        from MoinMoin.util import simpleIO
+
+        # Regenerate plain text
+        f = simpleIO()
+        h = htmllib.HTMLParser(formatter.AbstractFormatter(formatter.DumbWriter(f)))
+        h.feed(markup)
+        h.close()
+
+        return self.text(f.getvalue())
+
+    def escapedText(self, on, **kw):
+        """ This allows emitting text as-is, anything special will
+            be escaped (at least in HTML, some text output format
+            would possibly do nothing here)
+        """
+        return ""
+
+    def comment(self, text):
+        return ""
+
--- a/MoinMoin/formatter/base.py	Tue May 16 11:44:24 2006 +1200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,362 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - Formatter Base Class
-
-    @copyright: 2000 - 2004 by Jürgen Hermann <jh@web.de>
-    @license: GNU GPL, see COPYING for details.
-"""
-
-from MoinMoin import wikiutil
-import re, types
-
-class FormatterBase:
-    """ This defines the output interface used all over the rest of the code.
-
-        Note that no other means should be used to generate _content_ output,
-        while navigational elements (HTML page header/footer) and the like
-        can be printed directly without violating output abstraction.
-    """
-
-    hardspace = ' '
-
-    def __init__(self, request, **kw):
-        self.request = request
-        self._ = request.getText
-
-        self._store_pagelinks = kw.get('store_pagelinks', 0)
-        self._terse = kw.get('terse', 0)
-        self.pagelinks = []
-        self.in_p = 0
-        self.in_pre = 0
-        self._highlight_re = None
-        self._base_depth = 0
-
-    def set_highlight_re(self, hi_re=None):
-        if type(hi_re) in [types.StringType, types.UnicodeType]:
-            try:
-                self._highlight_re = re.compile(hi_re, re.U + re.IGNORECASE)
-            except re.error:
-                hi_re = re.escape(hi_re)
-                self._highlight_re = re.compile(hi_re, re.U + re.IGNORECASE)
-        else:
-            self._highlight_re = hi_re
-
-    def lang(self, on, lang_name):
-        return ""
-
-    def setPage(self, page):
-        self.page = page
-
-    def sysmsg(self, on, **kw):
-        """ Emit a system message (embed it into the page).
-
-            Normally used to indicate disabled options, or invalid markup.
-        """
-        return ""
-
-    # Document Level #####################################################
-    
-    def startDocument(self, pagename):
-        return ""
-
-    def endDocument(self):
-        return ""
-
-    def startContent(self, content_id="content", **kw):
-        return ""
-
-    def endContent(self):
-        return ""
-
-    # Links ##############################################################
-    
-    def pagelink(self, on, pagename='', page=None, **kw):
-        """ make a link to page <pagename>. Instead of supplying a pagename,
-            it is also possible to give a live Page object, then page.page_name
-            will be used.
-        """
-        if not self._store_pagelinks or not on or kw.get('generated'): 
-            return ''
-        if not pagename and page:
-            pagename = page.page_name
-        pagename = self.request.normalizePagename(pagename)
-        if pagename and pagename not in self.pagelinks:
-            self.pagelinks.append(pagename)
-
-    def interwikilink(self, on, interwiki='', pagename='', **kw):
-        """ calls pagelink() for internal interwikilinks
-            to make sure they get counted for self.pagelinks.
-            IMPORTANT: on and off must be called with same parameters, see
-                       also the text_html formatter.
-        """
-        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, '%s:%s' % (interwiki, pagename))
-        if wikitag == 'Self' or wikitag == self.request.cfg.interwikiname:
-            if wikitail.find('#') > -1:
-                wikitail, kw['anchor'] = wikitail.split('#', 1)
-                wikitail = wikiutil.url_unquote(wikitail)
-            return self.pagelink(on, wikitail, **kw)
-        return ''
-            
-    def url(self, on, url=None, css=None, **kw):
-        raise NotImplementedError
-
-    # Attachments ######################################################
-
-    def attachment_link(self, url, text, **kw):
-        raise NotImplementedError
-    def attachment_image(self, url, **kw):
-        raise NotImplementedError
-    def attachment_drawing(self, url, text, **kw):
-        raise NotImplementedError
-
-    def attachment_inlined(self, url, text, **kw):
-        from MoinMoin.action import AttachFile
-        import os
-        _ = self.request.getText
-        pagename, filename = AttachFile.absoluteName(url, self.page.page_name)
-        fname = wikiutil.taintfilename(filename)
-        fpath = AttachFile.getFilename(self.request, pagename, fname)
-        base, ext = os.path.splitext(filename)
-        Parser = wikiutil.getParserForExtension(self.request.cfg, ext)
-        if Parser is not None:
-            try:
-                content = file(fpath, 'r').read()
-                # Try to decode text. It might return junk, but we don't
-                # have enough information with attachments.
-                content = wikiutil.decodeUnknownInput(content)
-                colorizer = Parser(content, self.request)
-                colorizer.format(self)
-            except IOError:
-                pass
-
-        return self.attachment_link(url, text)
-
-    def anchordef(self, name):
-        return ""
-
-    def line_anchordef(self, lineno):
-        return ""
-
-    def anchorlink(self, on, name='', **kw):
-        return ""
-
-    def line_anchorlink(self, on, lineno=0):
-        return ""
-
-    def image(self, src=None, **kw):
-        """An inline image.
-
-        Extra keyword arguments are according to the HTML <img> tag attributes.
-        In particular an 'alt' or 'title' argument should give a description
-        of the image.
-        """
-        title = src
-        for titleattr in ('title', 'html__title', 'alt', 'html__alt'):
-            if kw.has_key(titleattr):
-                title = kw[titleattr]
-                break
-        if title:
-            return '[Image:%s]' % title
-        return '[Image]'
-
-    def smiley(self, text):
-        return text
-
-    def nowikiword(self, text):
-        return self.text(text)
-
-    # Text and Text Attributes ########################################### 
-    
-    def text(self, text, **kw):
-        if not self._highlight_re:
-            return self._text(text)
-            
-        result = []
-        lastpos = 0
-        match = self._highlight_re.search(text)
-        while match and lastpos < len(text):
-            # add the match we found
-            result.append(self._text(text[lastpos:match.start()]))
-            result.append(self.highlight(1))
-            result.append(self._text(match.group(0)))
-            result.append(self.highlight(0))
-
-            # search for the next one
-            lastpos = match.end() + (match.end() == lastpos)
-            match = self._highlight_re.search(text, lastpos)
-
-        result.append(self._text(text[lastpos:]))
-        return ''.join(result)
-
-    def _text(self, text):
-        raise NotImplementedError
-
-    def strong(self, on, **kw):
-        raise NotImplementedError
-
-    def emphasis(self, on, **kw):
-        raise NotImplementedError
-
-    def underline(self, on, **kw):
-        raise NotImplementedError
-
-    def highlight(self, on, **kw):
-        raise NotImplementedError
-
-    def sup(self, on, **kw):
-        raise NotImplementedError
-
-    def sub(self, on, **kw):
-        raise NotImplementedError
-
-    def strike(self, on, **kw):
-        raise NotImplementedError
-
-    def code(self, on, **kw):
-        raise NotImplementedError
-
-    def preformatted(self, on, **kw):
-        self.in_pre = on != 0
-
-    def small(self, on, **kw):
-        raise NotImplementedError
-
-    def big(self, on, **kw):
-        raise NotImplementedError
-
-    # special markup for syntax highlighting #############################
-
-    def code_area(self, on, code_id, **kw):
-        raise NotImplementedError
-
-    def code_line(self, on):
-        raise NotImplementedError
-
-    def code_token(self, tok_text, tok_type):
-        raise NotImplementedError
-
-    # Paragraphs, Lines, Rules ###########################################
-
-    def linebreak(self, preformatted=1):
-        raise NotImplementedError
-
-    def paragraph(self, on, **kw):
-        self.in_p = on != 0
-
-    def rule(self, size=0, **kw):
-        raise NotImplementedError
-
-    def icon(self, type):
-        return type
-
-    # Lists ##############################################################
-
-    def number_list(self, on, type=None, start=None, **kw):
-        raise NotImplementedError
-
-    def bullet_list(self, on, **kw):
-        raise NotImplementedError
-
-    def listitem(self, on, **kw):
-        raise NotImplementedError
-
-    def definition_list(self, on, **kw):
-        raise NotImplementedError
-
-    def definition_term(self, on, compact=0, **kw):
-        raise NotImplementedError
-
-    def definition_desc(self, on, **kw):
-        raise NotImplementedError
-
-    def heading(self, on, depth, **kw):
-        raise NotImplementedError
-
-    # Tables #############################################################
-    
-    def table(self, on, attrs={}, **kw):
-        raise NotImplementedError
-
-    def table_row(self, on, attrs={}, **kw):
-        raise NotImplementedError
-
-    def table_cell(self, on, attrs={}, **kw):
-        raise NotImplementedError
-
-    # Dynamic stuff / Plugins ############################################
-    
-    def macro(self, macro_obj, name, args):
-        # call the macro
-        return macro_obj.execute(name, args)    
-
-    def _get_bang_args(self, line):
-        if line[:2] == '#!':
-            try:
-                name, args = line[2:].split(None, 1)
-            except ValueError:
-                return ''
-            else:
-                return args
-        return None
-
-    def parser(self, parser_name, lines):
-        """ parser_name MUST be valid!
-            writes out the result instead of returning it!
-        """
-        parser = wikiutil.importPlugin(self.request.cfg, "parser", parser_name, "Parser")
-        args = self._get_bang_args(lines[0])
-        if args is not None:
-            lines = lines[1:]
-        p = parser('\n'.join(lines), self.request, format_args=args)
-        p.format(self)
-        del p
-        return ''
-
-    def dynamic_content(self, parser, callback, arg_list=[], arg_dict={},
-                        returns_content=1):
-        content = parser[callback](*arg_list, **arg_dict)
-        if returns_content:
-            return content
-        else:
-            return ''
-
-    # Other ##############################################################
-    
-    def div(self, on, **kw):
-        """ open/close a blocklevel division """
-        return ""
-    
-    def span(self, on, **kw):
-        """ open/close a inline span """
-        return ""
-    
-    def rawHTML(self, markup):
-        """ This allows emitting pre-formatted HTML markup, and should be
-            used wisely (i.e. very seldom).
-
-            Using this event while generating content results in unwanted
-            effects, like loss of markup or insertion of CDATA sections
-            when output goes to XML formats.
-        """
-
-        import formatter, htmllib
-        from MoinMoin.util import simpleIO
-
-        # Regenerate plain text
-        f = simpleIO()
-        h = htmllib.HTMLParser(formatter.AbstractFormatter(formatter.DumbWriter(f)))
-        h.feed(markup)
-        h.close()
-
-        return self.text(f.getvalue())
-
-    def escapedText(self, on, **kw):
-        """ This allows emitting text as-is, anything special will
-            be escaped (at least in HTML, some text output format
-            would possibly do nothing here)
-        """
-        return ""
-
-    def comment(self, text):
-        return ""
-
--- a/MoinMoin/formatter/dom_xml.py	Tue May 16 11:44:24 2006 +1200
+++ b/MoinMoin/formatter/dom_xml.py	Wed May 17 09:27:26 2006 +1200
@@ -9,7 +9,7 @@
 line_anchors = True
 
 from xml.dom import minidom
-from MoinMoin.formatter.base import FormatterBase
+from MoinMoin.formatter import FormatterBase
 
 #def print_dom(element, indent=''):
 #    print indent + element.tagName
--- a/MoinMoin/formatter/pagelinks.py	Tue May 16 11:44:24 2006 +1200
+++ b/MoinMoin/formatter/pagelinks.py	Wed May 17 09:27:26 2006 +1200
@@ -6,7 +6,7 @@
     @license: GNU GPL, see COPYING for details.
 """
 
-from MoinMoin.formatter.base import FormatterBase
+from MoinMoin.formatter import FormatterBase
 
 class Formatter(FormatterBase):
     """ Collect pagelinks and format nothing :-) """        
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/formatter/text_docbook.py	Wed May 17 09:27:26 2006 +1200
@@ -0,0 +1,593 @@
+# -*- coding: utf-8 -*-
+"""
+    MoinMoin - DocBook Formatter
+
+    @copyright: 2005 by Mikko Virkkil <mvirkkil@cc.hut.fi>
+    @copyright: 2005 by MoinMoin:AlexanderSchremmer (small modifications)
+    @copyright: 2005 by MoinMoin:Petr Pytelka <pyta@lightcomp.com> (small modifications)
+    
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import sys, traceback, os
+
+from MoinMoin.formatter import FormatterBase
+from MoinMoin import wikiutil, config
+from MoinMoin.error import CompositeError
+from MoinMoin.action import AttachFile
+
+from xml.sax import saxutils
+from xml.dom import getDOMImplementation
+
+class InternalError(CompositeError): pass
+
+try:
+    dom = getDOMImplementation("4DOM")
+except ImportError:
+    raise InternalError("You need to install PyXML to use the DocBook formatter.")
+
+class DocBookOutputFormatter:
+    """
+       Format docbook output
+    """
+    
+    def __init__(self, dommDoc):
+        self.doc = dommDoc
+        self.curNode = dommDoc.documentElement
+        
+    def setHeading(self, headNode):
+        self.domHeadNode = headNode
+        return u""
+    
+    def _printNode(self, node):
+        """
+            Function print a node
+        """
+        from xml.dom.ext import Print
+        import StringIO
+        from xml.dom.ext import Printer
+        
+        stream = StringIO.StringIO()
+        
+        visitor = Printer.PrintVisitor(stream, 'UTF-8')
+        Printer.PrintWalker(visitor, node).run()
+        # get value from stream
+        ret = stream.getvalue()
+        stream.close()
+        
+        return unicode(ret, 'utf-8')
+
+    def getHeading(self):
+        # return heading from model
+        rootNode = self.doc.documentElement
+        # print article info
+        return '<?xml version="1.0"?><%s>%s' % (rootNode.nodeName,
+                                                self._printNode(self.domHeadNode))
+        
+    def getBody(self):
+        body = []
+        # print all nodes inside dom behind heading
+        firstNode = self.doc.documentElement.firstChild
+        while firstNode:
+            if firstNode != self.domHeadNode:
+                body.append(self._printNode(firstNode))
+            firstNode = firstNode.nextSibling
+        return ''.join(body)
+
+    def getEndContent(self):
+        # close all opened tags
+        ret = []
+        while self.curNode != self.doc.documentElement:
+            ret.append("</%s>" % (self.curNode.nodeName, ))
+            self.curNode = self.curNode.parentNode
+        return ''.join(ret)
+        
+    def getFooter(self):
+        return "</%s>" % self.doc.documentElement.nodeName
+
+class Formatter(FormatterBase):
+    """
+        Send plain text data.
+    """
+
+    section_should_break = ['abstract', 'para', 'emphasis']
+
+    def __init__(self, request, **kw):
+        '''We should use this for creating the doc'''
+        FormatterBase.__init__(self, request, **kw)
+
+        self.doc = dom.createDocument(None, "article", dom.createDocumentType(
+            "article", "-//OASIS//DTD DocBook V4.4//EN",
+            "http://www.docbook.org/xml/4.4/docbookx.dtd"))
+        self.root = self.doc.documentElement
+        self.curdepth = 0
+        self.outputFormatter = DocBookOutputFormatter(self.doc)
+        self.exchangeKeys = []
+        self.exchangeValues = []
+
+    def startDocument(self, pagename):
+        info = self.doc.createElement("articleinfo")
+        title = self.doc.createElement("title")
+        title.appendChild(self.doc.createTextNode(pagename))
+        info.appendChild(title)
+        self.root.appendChild(info)
+        # set heading node
+        self.outputFormatter.setHeading(info)
+        
+        return self.outputFormatter.getHeading()
+
+    def startContent(self, content_id="content", **kw):
+        self.cur = self.root
+        return ""
+
+    def endContent(self):
+        bodyStr = self.outputFormatter.getBody()
+        # exchange all strings in body
+        i = 0
+        while i < len(self.exchangeKeys):
+            bodyStr = bodyStr.replace(self.exchangeKeys[i], self.exchangeValues[i])
+            i += 1
+        return bodyStr + self.outputFormatter.getEndContent()
+
+    def endDocument(self):
+        return self.outputFormatter.getFooter()
+
+    def text(self, text, **kw):
+        if text == "\\n":
+            srcText = "\n"
+        else:
+            srcText = text
+        if self.cur.nodeName == "screen":
+            if self.cur.lastChild != None:
+                from xml.dom.ext import Node
+                if self.cur.lastChild.nodeType == Node.CDATA_SECTION_NODE:
+                    self.cur.lastChild.nodeValue = self.cur.lastChild.nodeValue + srcText
+            else:
+                self.cur.appendChild(self.doc.createCDATASection(srcText))
+        else:
+            self.cur.appendChild(self.doc.createTextNode(srcText))
+        return ""
+
+    def heading(self, on, depth, **kw):
+        while self.cur.nodeName in self.section_should_break:
+            self.cur = self.cur.parentNode
+               
+        if on:
+            # try to go to higher level if needed
+            if depth <= self.curdepth:
+                # number of levels we want to go higher
+                numberOfLevels = self.curdepth-depth + 1
+                for i in range(numberOfLevels):
+                    #find first non section node
+                    while (self.cur.nodeName != "section" and self.cur.nodeName != "article"):
+                        self.cur = self.cur.parentNode
+
+# I don't understand this code - looks like unnecessary -- maybe it is used to gain some vertical space for large headings?
+#                    if len(self.cur.childNodes) < 3:
+#                       self._addEmptyNode("para")
+                    
+                    # check if not top-level
+                    if self.cur.nodeName != "article":
+                        self.cur = self.cur.parentNode
+
+            section = self.doc.createElement("section")
+            self.cur.appendChild(section)
+            self.cur = section
+
+            title = self.doc.createElement("title")
+            self.cur.appendChild(title)
+            self.cur = title
+            self.curdepth = depth
+        else:
+            self.cur = self.cur.parentNode
+
+        return ""
+
+    def paragraph(self, on, **kw):
+        FormatterBase.paragraph(self, on)
+        if on:
+            para = self.doc.createElement("para")
+            self.cur.appendChild(para)
+            self.cur = para
+        else:
+            self.cur = self.cur.parentNode
+        return ""
+
+    def linebreak(self, preformatted=1):
+        if preformatted:
+            self.text('\\n')
+        else:
+            #this should not happen
+            #self.text('CRAP') 
+            pass
+        return ""
+
+    def _handleNode(self, name, on, attributes=()):
+        if on:
+            node = self.doc.createElement(name)
+            self.cur.appendChild(node)
+            if len(attributes) > 0:
+                for name, value in attributes:
+                    node.setAttribute(name, value)
+            self.cur = node
+        else:
+            self.cur = self.cur.parentNode
+        return ""
+
+    def _addEmptyNode(self, name, attributes=()):
+        node = self.doc.createElement(name)
+        self.cur.appendChild(node)
+        if len(attributes) > 0:
+            for name, value in attributes:
+                node.setAttribute(name, value)
+
+    def _getTableCellCount(self, attrs=()):
+        cols = 1
+        if attrs and attrs.has_key('colspan'):
+            s1 = attrs['colspan']
+            s1 = str(s1).replace('"','')
+            cols = int(s1)
+        return cols
+
+    def _addTableCellDefinition(self, attrs=()):
+        # Check number of columns
+        cols = self._getTableCellCount(attrs)
+        # Find node tgroup
+        actNode = self.cur
+        numberExistingColumns = 0
+        while actNode and actNode.nodeName != 'tgroup':
+            actNode = actNode.parentNode
+        # Number of existing columns
+        nodeBefore = self.cur
+        if actNode:
+            nodeBefore = actNode.firstChild
+        while nodeBefore and nodeBefore.nodeName != 'tbody':
+            nodeBefore = nodeBefore.nextSibling
+            numberExistingColumns += 1
+
+        while cols >= 1:
+            # Create new node
+            numberExistingColumns += 1
+            nnode = self.doc.createElement("colspec")
+            nnode.setAttribute('colname', 'xxx' + str(numberExistingColumns))
+            # Add node
+            if actNode:
+                actNode.insertBefore(nnode, nodeBefore)
+            else:
+                self.cur.insertBefore(nnode, nodeBefore)
+            cols -= 1
+        # Set new number of columns for tgroup
+        self.cur.parentNode.parentNode.parentNode.setAttribute('cols', str(numberExistingColumns))
+        return ""
+
+### Inline ##########################################################
+
+    def _handleFormatting(self, name, on, attributes=()):
+        # We add all the elements we create to the list of elements that should not contain a section        
+        if name not in self.section_should_break:
+            self.section_should_break.append(name)
+
+        return self._handleNode(name, on, attributes)
+
+    def strong(self, on, **kw):
+        return self._handleFormatting("emphasis", on, (('role','strong'), ))
+
+    def emphasis(self, on, **kw):
+        return self._handleFormatting("emphasis", on)
+
+    def underline(self, on, **kw):
+        return self._handleFormatting("emphasis", on, (('role','underline'), ))
+
+    def highlight(self, on, **kw):
+        return self._handleFormatting("emphasis", on, (('role','highlight'), ))
+
+    def sup(self, on, **kw):
+        return self._handleFormatting("superscript", on)
+
+    def sub(self, on, **kw):
+        return self._handleFormatting("subscript", on)
+
+    def strike(self, on, **kw):
+        # does not yield <strike> using the HTML XSLT files here ...
+        # but seems to be correct
+        return self._handleFormatting("emphasis", on,
+                                      (('role','strikethrough'), ))
+
+    def code(self, on, **kw):
+        return self._handleFormatting("code", on)
+
+    def preformatted(self, on, **kw):
+        return self._handleFormatting("screen", on)
+
+
+### Lists ###########################################################
+
+    def number_list(self, on, type=None, start=None, **kw):
+        docbook_ol_types = {'1': "arabic", 
+                            'a': "loweralpha", 
+                            'A': "upperalpha",
+                            'i': "lowerroman",
+                            'I': "upperroman"}
+
+        if type and docbook_ol_types.has_key(type):
+            attrs = [("numeration", docbook_ol_types[type])]
+        else:
+            attrs = []
+
+        return self._handleNode('orderedlist', on, attrs)
+
+    def bullet_list(self, on, **kw):
+        return self._handleNode("itemizedlist", on)
+
+    def definition_list(self, on, **kw):
+        return self._handleNode("glosslist", on)        
+
+    def definition_term(self, on, compact=0, **kw):
+       # When on is false, we back out just on level. This is
+       # ok because we know definition_desc gets called, and we
+       # back out two levels there.
+        if on:
+            entry=self.doc.createElement('glossentry')
+            term=self.doc.createElement('glossterm')
+            entry.appendChild(term)
+            self.cur.appendChild(entry)
+            self.cur = term
+        else:
+            self.cur = self.cur.parentNode
+        return ""
+   
+    def definition_desc(self, on, **kw):
+        # We backout two levels when 'on' is false, to leave the glossentry stuff
+        if on:
+            return self._handleNode("glossdef", on)
+        else:
+            self.cur = self.cur.parentNode.parentNode
+            return ""
+
+    def listitem(self, on, **kw):
+        if on:
+            node = self.doc.createElement("listitem")
+            self.cur.appendChild(node)
+            self.cur = node
+        else:
+            self.cur = self.cur.parentNode
+        return ""
+
+
+### Links ###########################################################
+
+    # FIXME: This is quite crappy
+    def pagelink(self, on, pagename='', page=None, **kw):
+        FormatterBase.pagelink(self, on, pagename, page, **kw)
+
+        return self.interwikilink(on, 'Self', pagename) # FIXME
+
+    # FIXME: This is even more crappy
+    def interwikilink(self, on, interwiki='', pagename='', **kw):
+        if not on:
+            return self.url(on,kw)
+
+        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, '%s:%s' % (interwiki, pagename))
+        wikiurl = wikiutil.mapURL(self.request, wikiurl)
+        href = wikiutil.join_wiki(wikiurl, wikitail)
+
+        return self.url(on, href)
+            
+    def url(self, on, url=None, css=None, **kw):
+        return self._handleNode("ulink", on, (('url', url), ))
+
+    def anchordef(self, name):
+        self._handleNode("anchor", True, (('id', name), ))
+        self._handleNode("ulink", False)
+        return ""
+
+    def anchorlink(self, on, name='', **kw):
+        id = kw.get('id',None)
+        attrs = []
+        if name != '':
+            attrs.append(('endterm', name))
+        if id != None:
+            attrs.append(('linkend', id))
+        elif name != '':
+            attrs.append(('linkend', name))
+
+        return self._handleNode("link", on, attrs)
+
+### Attachments ######################################################
+
+    def attachment_link(self, url, text, **kw):
+        _ = self.request.getText
+        pagename, filename = AttachFile.absoluteName(url, self.page.page_name)
+        fname = wikiutil.taintfilename(filename)
+        fpath = AttachFile.getFilename(self.request, pagename, fname)
+        target = AttachFile.getAttachUrl(pagename, filename, self.request)
+        if not os.path.exists(fpath):
+            return self.text("[attachment:%s]" % url)
+        else:
+            return (self.url(1, target, title="attachment:%s" % url) +
+                    self.text(text) +
+                    self.url(0))
+
+    def attachment_image(self, url, **kw):
+        _ = self.request.getText
+        pagename, filename = AttachFile.absoluteName(url, self.page.page_name)
+        fname = wikiutil.taintfilename(filename)
+        fpath = AttachFile.getFilename(self.request, pagename, fname)
+        if not os.path.exists(fpath):
+            return self.text("[attachment:%s]" % url)
+        else:
+            return self.image(
+                title="attachment:%s" % url,
+                src=AttachFile.getAttachUrl(pagename, filename,
+                                            self.request, addts=1))
+
+    def attachment_drawing(self, url, text, **kw):
+        _ = self.request.getText
+        pagename, filename = AttachFile.absoluteName(url, self.page.page_name)
+        fname = wikiutil.taintfilename(filename)
+        drawing = fname
+        fname = fname + ".png"
+        filename = filename + ".png"
+        if not os.path.exists(fpath):
+            return self.text("[drawing:%s]" % url)
+        else:
+            return self.image(
+                alt=drawing,
+                src=AttachFile.getAttachUrl(pagename, filename, self.request,
+                                            addts=1),
+                html_class="drawing")
+
+### Images and Smileys ##############################################
+
+    def image(self, src=None, **kw):
+        if src:
+            kw['src'] = src
+        media = self.doc.createElement('inlinemediaobject')
+
+        imagewrap = self.doc.createElement('imageobject')
+        media.appendChild(imagewrap)
+
+        image = self.doc.createElement('imagedata')
+        if kw.has_key('src'):
+            image.setAttribute('fileref', kw['src'])
+        if kw.has_key('width'):
+            image.setAttribute('width', kw['width'])
+        if kw.has_key('height'):
+            image.setAttribute('depth', kw['height'])
+        imagewrap.appendChild(image)
+
+        title = ''
+        for a in ('title', 'html_title', 'alt', 'html_alt'):
+            if kw.has_key(a):
+                title = kw[a]
+                break
+        if title:
+            txtcontainer = self.doc.createElement('textobject')
+            media.appendChild(txtcontainer)        
+            txtphrase = self.doc.createElement('phrase')
+            txtphrase.appendChild(self.doc.createTextNode(title))
+            txtcontainer.appendChild(txtphrase)        
+        
+        self.cur.appendChild(media)
+        return ""        
+ 
+    def smiley(self, text):
+        w, h, b, img = config.smileys[text.strip()]
+        href = img
+        if not href.startswith('/'):
+            href = self.request.theme.img_url(img)
+        return self.image(src=href, alt=text, width=str(w), height=str(h))
+
+    def icon(self, type):
+        return '' # self.request.theme.make_icon(type)
+
+### Tables ##########################################################
+
+    #FIXME: We should copy code from text_html.py for attr handling
+
+    def table(self, on, attrs=None, **kw):
+        sanitized_attrs = []
+        if attrs and attrs.has_key('id'):
+            sanitized_attrs[id] = attrs['id']
+
+        self._handleNode("table", on, sanitized_attrs)
+        if on:
+            self._addEmptyNode("caption") #dtd for table requires caption		
+        self._handleNode("tgroup", on)
+        self._handleNode("tbody", on)
+        return ""
+    
+    def table_row(self, on, attrs=None, **kw):
+        self.table_current_row_cells = 0
+        sanitized_attrs = []
+        if attrs and attrs.has_key('id'):
+            sanitized_attrs[id] = attrs['id']
+        return self._handleNode("row", on, sanitized_attrs)
+
+    def table_cell(self, on, attrs=None, **kw):
+        # Finish row definition
+        sanitized_attrs = []
+        if attrs and attrs.has_key('id'):
+            sanitized_attrs[id] = attrs['id']
+        # Get number of newly added columns
+        startCount = self.table_current_row_cells
+        addedCellsCount = self._getTableCellCount(attrs)
+        self.table_current_row_cells += addedCellsCount
+        ret = self._handleNode("entry", on, sanitized_attrs)
+        if self.cur.parentNode == self.cur.parentNode.parentNode.firstChild:
+            self._addTableCellDefinition(attrs)
+        # Set cell join if any
+        if addedCellsCount > 1:
+            startString = "xxx" + str(startCount)
+            stopString = "xxx" + str(startCount + addedCellsCount - 1)
+            self.cur.setAttribute("namest", startString)
+            self.cur.setAttribute("nameend", stopString)
+        return ret
+
+### Code ############################################################
+
+    def code_area(self, on, code_id, code_type='code', show=0, start=-1, step=-1):
+        show = show and 'numbered' or 'unnumbered'
+        if start < 1:
+            start = 1
+        
+        attrs = (('id', code_id),
+                ('linenumbering', show),
+                ('startinglinenumber', str(start)),
+                ('language', code_type),
+                ('format','linespecific'),
+                )
+        return self._handleFormatting("screen", on, attrs)
+
+    def code_line(self, on):
+        return '' # No clue why something should be done here
+
+    def code_token(self, on, tok_type):
+        toks_map = {'ID':'methodname',
+                    'Operator':'',
+                    'Char':'',
+                    'Comment':'lineannotation',
+                    'Number':'',
+                    'String':'phrase',
+                    'SPChar':'',
+                    'ResWord':'token',
+                    'ConsWord':'symbol',
+                    'Error':'errortext',
+                    'ResWord2':'',
+                    'Special':'',
+                    'Preprc':'',
+                    'Text':''}
+        if toks_map.has_key(tok_type) and toks_map[tok_type] != '':
+            return self._handleFormatting(toks_map[tok_type], on)
+        else:
+            return ""
+
+    def macro(self, macro_obj, name, args):
+        if name == "TableOfContents":
+            # Table of content can be inserted in docbook transformation
+            return u""
+        # output of all macros is added as the text node
+        # At the begining text mode contain some string which is later
+        # exchange for real value. There is problem that data inserted
+        # as text mode are encoded to xml, e.g. < is encoded in the output as &lt;
+        text = FormatterBase.macro(self, macro_obj, name, args)
+        if len(text) > 0:
+            # prepare identificator
+            sKey = "EXCHANGESTRINGMACRO-" + str(len(self.exchangeKeys)) + "-EXCHANGESTRINGMACRO"
+            self.exchangeKeys.append(sKey)
+            self.exchangeValues.append(text)
+            # append data to lists
+            self.text(sKey)
+        return u""
+
+### Not supported ###################################################
+
+    def rule(self, size = 0, **kw):
+        return ""
+
+    def small(self, on, **kw):
+        return ""
+
+    def big(self, on, **kw):
+        return ""
+
--- a/MoinMoin/formatter/text_gedit.py	Tue May 16 11:44:24 2006 +1200
+++ b/MoinMoin/formatter/text_gedit.py	Wed May 17 09:27:26 2006 +1200
@@ -6,8 +6,7 @@
     @license: GNU GPL, see COPYING for details.
 """
 
-from MoinMoin.formatter import text_html
-from MoinMoin.formatter.base import FormatterBase
+from MoinMoin.formatter import FormatterBase, text_html
 from MoinMoin import wikiutil, config
 from MoinMoin.Page import Page
 from MoinMoin.action import AttachFile
@@ -53,7 +52,7 @@
         if not on:
             return self.url(0) # return '</a>'
         html_class = 'badinterwiki' # we use badinterwiki in any case to simplify reverse conversion
-        href = wikiutil.quoteWikinameURL(pagename)
+        href = wikiutil.quoteWikinameURL(pagename) or "/" # FCKeditor behaves strange on empty href
         title = kw.get('title', interwiki)
         return self.url(1, href, title=title, do_escape=1, css=html_class) # interwiki links with pages with umlauts
 
--- a/MoinMoin/formatter/text_html.py	Tue May 16 11:44:24 2006 +1200
+++ b/MoinMoin/formatter/text_html.py	Wed May 17 09:27:26 2006 +1200
@@ -7,7 +7,7 @@
 """
 import os.path, re
 from sets import Set # TODO: when we require Python 2.4+ use the builtin 'set' type
-from MoinMoin.formatter.base import FormatterBase
+from MoinMoin.formatter import FormatterBase
 from MoinMoin import wikiutil, i18n, config
 from MoinMoin.Page import Page
 from MoinMoin.action import AttachFile
@@ -726,10 +726,6 @@
                                      title="%s" % (_('Edit drawing %(filename)s') % {'filename': self.text(fname)}))
         
     
-    # def attachment_inlined(self, url, text, **kw):
-    # moved to MoinMoin/formatter/base.py
-
-
     # Text ##############################################################
     
     def _text(self, text):
--- a/MoinMoin/formatter/text_plain.py	Tue May 16 11:44:24 2006 +1200
+++ b/MoinMoin/formatter/text_plain.py	Wed May 17 09:27:26 2006 +1200
@@ -6,7 +6,7 @@
     @license: GNU GPL, see COPYING for details.
 """
 
-from MoinMoin.formatter.base import FormatterBase
+from MoinMoin.formatter import FormatterBase
 
 class Formatter(FormatterBase):
     """
--- a/MoinMoin/formatter/text_python.py	Tue May 16 11:44:24 2006 +1200
+++ b/MoinMoin/formatter/text_python.py	Wed May 17 09:27:26 2006 +1200
@@ -184,9 +184,14 @@
         """ parser_name MUST be valid!
             prints out the result instead of returning it!
         """
-        try:
-            Dependencies = wikiutil.importPlugin(self.request.cfg, "parser", parser_name, "Dependencies")
-        except wikiutil.PluginAttributeError:
+        mt = wikiutil.MimeType(parser_name)
+        for module_name in mt.module_name():
+            try:
+                Dependencies = wikiutil.importPlugin(self.request.cfg, "parser", module_name, "Dependencies")
+                break
+            except wikiutil.PluginAttributeError:
+                pass
+        else:
             Dependencies = self.defaultDependencies
         if self.__is_static(Dependencies):
             return self.formatter.parser(parser_name, lines)
--- a/MoinMoin/formatter/text_xml.py	Tue May 16 11:44:24 2006 +1200
+++ b/MoinMoin/formatter/text_xml.py	Wed May 17 09:27:26 2006 +1200
@@ -7,7 +7,7 @@
 """
 
 from xml.sax import saxutils
-from MoinMoin.formatter.base import FormatterBase
+from MoinMoin.formatter import FormatterBase
 from MoinMoin import config
 from MoinMoin.Page import Page
 
--- a/MoinMoin/formatter/xml_docbook.py	Tue May 16 11:44:24 2006 +1200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,593 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-    MoinMoin - DocBook Formatter
-
-    @copyright: 2005 by Mikko Virkkil <mvirkkil@cc.hut.fi>
-    @copyright: 2005 by MoinMoin:AlexanderSchremmer (small modifications)
-    @copyright: 2005 by MoinMoin:Petr Pytelka <pyta@lightcomp.com> (small modifications)
-    
-    @license: GNU GPL, see COPYING for details.
-"""
-
-import sys, traceback, os
-
-from MoinMoin.formatter.base import FormatterBase
-from MoinMoin import wikiutil, config
-from MoinMoin.error import CompositeError
-from MoinMoin.action import AttachFile
-
-from xml.sax import saxutils
-from xml.dom import getDOMImplementation
-
-class InternalError(CompositeError): pass
-
-try:
-    dom = getDOMImplementation("4DOM")
-except ImportError:
-    raise InternalError("You need to install PyXML to use the DocBook formatter.")
-
-class DocBookOutputFormatter:
-    """
-       Format docbook output
-    """
-    
-    def __init__(self, dommDoc):
-        self.doc = dommDoc
-        self.curNode = dommDoc.documentElement
-        
-    def setHeading(self, headNode):
-        self.domHeadNode = headNode
-        return u""
-    
-    def _printNode(self, node):
-        """
-            Function print a node
-        """
-        from xml.dom.ext import Print
-        import StringIO
-        from xml.dom.ext import Printer
-        
-        stream = StringIO.StringIO()
-        
-        visitor = Printer.PrintVisitor(stream, 'UTF-8')
-        Printer.PrintWalker(visitor, node).run()
-        # get value from stream
-        ret = stream.getvalue()
-        stream.close()
-        
-        return unicode(ret, 'utf-8')
-
-    def getHeading(self):
-        # return heading from model
-        rootNode = self.doc.documentElement
-        # print article info
-        return '<?xml version="1.0"?><%s>%s' % (rootNode.nodeName,
-                                                self._printNode(self.domHeadNode))
-        
-    def getBody(self):
-        body = []
-        # print all nodes inside dom behind heading
-        firstNode = self.doc.documentElement.firstChild
-        while firstNode:
-            if firstNode != self.domHeadNode:
-                body.append(self._printNode(firstNode))
-            firstNode = firstNode.nextSibling
-        return ''.join(body)
-
-    def getEndContent(self):
-        # close all opened tags
-        ret = []
-        while self.curNode != self.doc.documentElement:
-            ret.append("</%s>" % (self.curNode.nodeName, ))
-            self.curNode = self.curNode.parentNode
-        return ''.join(ret)
-        
-    def getFooter(self):
-        return "</%s>" % self.doc.documentElement.nodeName
-
-class Formatter(FormatterBase):
-    """
-        Send plain text data.
-    """
-
-    section_should_break = ['abstract', 'para', 'emphasis']
-
-    def __init__(self, request, **kw):
-        '''We should use this for creating the doc'''
-        FormatterBase.__init__(self, request, **kw)
-
-        self.doc = dom.createDocument(None, "article", dom.createDocumentType(
-            "article", "-//OASIS//DTD DocBook V4.4//EN",
-            "http://www.docbook.org/xml/4.4/docbookx.dtd"))
-        self.root = self.doc.documentElement
-        self.curdepth = 0
-        self.outputFormatter = DocBookOutputFormatter(self.doc)
-        self.exchangeKeys = []
-        self.exchangeValues = []
-
-    def startDocument(self, pagename):
-        info = self.doc.createElement("articleinfo")
-        title = self.doc.createElement("title")
-        title.appendChild(self.doc.createTextNode(pagename))
-        info.appendChild(title)
-        self.root.appendChild(info)
-        # set heading node
-        self.outputFormatter.setHeading(info)
-        
-        return self.outputFormatter.getHeading()
-
-    def startContent(self, content_id="content", **kw):
-        self.cur = self.root
-        return ""
-
-    def endContent(self):
-        bodyStr = self.outputFormatter.getBody()
-        # exchange all strings in body
-        i = 0
-        while i < len(self.exchangeKeys):
-            bodyStr = bodyStr.replace(self.exchangeKeys[i], self.exchangeValues[i])
-            i += 1
-        return bodyStr + self.outputFormatter.getEndContent()
-
-    def endDocument(self):
-        return self.outputFormatter.getFooter()
-
-    def text(self, text, **kw):
-        if text == "\\n":
-            srcText = "\n"
-        else:
-            srcText = text
-        if self.cur.nodeName == "screen":
-            if self.cur.lastChild != None:
-                from xml.dom.ext import Node
-                if self.cur.lastChild.nodeType == Node.CDATA_SECTION_NODE:
-                    self.cur.lastChild.nodeValue = self.cur.lastChild.nodeValue + srcText
-            else:
-                self.cur.appendChild(self.doc.createCDATASection(srcText))
-        else:
-            self.cur.appendChild(self.doc.createTextNode(srcText))
-        return ""
-
-    def heading(self, on, depth, **kw):
-        while self.cur.nodeName in self.section_should_break:
-            self.cur = self.cur.parentNode
-               
-        if on:
-            # try to go to higher level if needed
-            if depth <= self.curdepth:
-                # number of levels we want to go higher
-                numberOfLevels = self.curdepth-depth + 1
-                for i in range(numberOfLevels):
-                    #find first non section node
-                    while (self.cur.nodeName != "section" and self.cur.nodeName != "article"):
-                        self.cur = self.cur.parentNode
-
-# I don't understand this code - looks like unnecessary -- maybe it is used to gain some vertical space for large headings?
-#                    if len(self.cur.childNodes) < 3:
-#                       self._addEmptyNode("para")
-                    
-                    # check if not top-level
-                    if self.cur.nodeName != "article":
-                        self.cur = self.cur.parentNode
-
-            section = self.doc.createElement("section")
-            self.cur.appendChild(section)
-            self.cur = section
-
-            title = self.doc.createElement("title")
-            self.cur.appendChild(title)
-            self.cur = title
-            self.curdepth = depth
-        else:
-            self.cur = self.cur.parentNode
-
-        return ""
-
-    def paragraph(self, on, **kw):
-        FormatterBase.paragraph(self, on)
-        if on:
-            para = self.doc.createElement("para")
-            self.cur.appendChild(para)
-            self.cur = para
-        else:
-            self.cur = self.cur.parentNode
-        return ""
-
-    def linebreak(self, preformatted=1):
-        if preformatted:
-            self.text('\\n')
-        else:
-            #this should not happen
-            #self.text('CRAP') 
-            pass
-        return ""
-
-    def _handleNode(self, name, on, attributes=()):
-        if on:
-            node = self.doc.createElement(name)
-            self.cur.appendChild(node)
-            if len(attributes) > 0:
-                for name, value in attributes:
-                    node.setAttribute(name, value)
-            self.cur = node
-        else:
-            self.cur = self.cur.parentNode
-        return ""
-
-    def _addEmptyNode(self, name, attributes=()):
-        node = self.doc.createElement(name)
-        self.cur.appendChild(node)
-        if len(attributes) > 0:
-            for name, value in attributes:
-                node.setAttribute(name, value)
-
-    def _getTableCellCount(self, attrs=()):
-        cols = 1
-        if attrs and attrs.has_key('colspan'):
-            s1 = attrs['colspan']
-            s1 = str(s1).replace('"','')
-            cols = int(s1)
-        return cols
-
-    def _addTableCellDefinition(self, attrs=()):
-        # Check number of columns
-        cols = self._getTableCellCount(attrs)
-        # Find node tgroup
-        actNode = self.cur
-        numberExistingColumns = 0
-        while actNode and actNode.nodeName != 'tgroup':
-            actNode = actNode.parentNode
-        # Number of existing columns
-        nodeBefore = self.cur
-        if actNode:
-            nodeBefore = actNode.firstChild
-        while nodeBefore and nodeBefore.nodeName != 'tbody':
-            nodeBefore = nodeBefore.nextSibling
-            numberExistingColumns += 1
-
-        while cols >= 1:
-            # Create new node
-            numberExistingColumns += 1
-            nnode = self.doc.createElement("colspec")
-            nnode.setAttribute('colname', 'xxx' + str(numberExistingColumns))
-            # Add node
-            if actNode:
-                actNode.insertBefore(nnode, nodeBefore)
-            else:
-                self.cur.insertBefore(nnode, nodeBefore)
-            cols -= 1
-        # Set new number of columns for tgroup
-        self.cur.parentNode.parentNode.parentNode.setAttribute('cols', str(numberExistingColumns))
-        return ""
-
-### Inline ##########################################################
-
-    def _handleFormatting(self, name, on, attributes=()):
-        # We add all the elements we create to the list of elements that should not contain a section        
-        if name not in self.section_should_break:
-            self.section_should_break.append(name)
-
-        return self._handleNode(name, on, attributes)
-
-    def strong(self, on, **kw):
-        return self._handleFormatting("emphasis", on, (('role','strong'), ))
-
-    def emphasis(self, on, **kw):
-        return self._handleFormatting("emphasis", on)
-
-    def underline(self, on, **kw):
-        return self._handleFormatting("emphasis", on, (('role','underline'), ))
-
-    def highlight(self, on, **kw):
-        return self._handleFormatting("emphasis", on, (('role','highlight'), ))
-
-    def sup(self, on, **kw):
-        return self._handleFormatting("superscript", on)
-
-    def sub(self, on, **kw):
-        return self._handleFormatting("subscript", on)
-
-    def strike(self, on, **kw):
-        # does not yield <strike> using the HTML XSLT files here ...
-        # but seems to be correct
-        return self._handleFormatting("emphasis", on,
-                                      (('role','strikethrough'), ))
-
-    def code(self, on, **kw):
-        return self._handleFormatting("code", on)
-
-    def preformatted(self, on, **kw):
-        return self._handleFormatting("screen", on)
-
-
-### Lists ###########################################################
-
-    def number_list(self, on, type=None, start=None, **kw):
-        docbook_ol_types = {'1': "arabic", 
-                            'a': "loweralpha", 
-                            'A': "upperalpha",
-                            'i': "lowerroman",
-                            'I': "upperroman"}
-
-        if type and docbook_ol_types.has_key(type):
-            attrs = [("numeration", docbook_ol_types[type])]
-        else:
-            attrs = []
-
-        return self._handleNode('orderedlist', on, attrs)
-
-    def bullet_list(self, on, **kw):
-        return self._handleNode("itemizedlist", on)
-
-    def definition_list(self, on, **kw):
-        return self._handleNode("glosslist", on)        
-
-    def definition_term(self, on, compact=0, **kw):
-       # When on is false, we back out just on level. This is
-       # ok because we know definition_desc gets called, and we
-       # back out two levels there.
-        if on:
-            entry=self.doc.createElement('glossentry')
-            term=self.doc.createElement('glossterm')
-            entry.appendChild(term)
-            self.cur.appendChild(entry)
-            self.cur = term
-        else:
-            self.cur = self.cur.parentNode
-        return ""
-   
-    def definition_desc(self, on, **kw):
-        # We backout two levels when 'on' is false, to leave the glossentry stuff
-        if on:
-            return self._handleNode("glossdef", on)
-        else:
-            self.cur = self.cur.parentNode.parentNode
-            return ""
-
-    def listitem(self, on, **kw):
-        if on:
-            node = self.doc.createElement("listitem")
-            self.cur.appendChild(node)
-            self.cur = node
-        else:
-            self.cur = self.cur.parentNode
-        return ""
-
-
-### Links ###########################################################
-
-    # FIXME: This is quite crappy
-    def pagelink(self, on, pagename='', page=None, **kw):
-        FormatterBase.pagelink(self, on, pagename, page, **kw)
-
-        return self.interwikilink(on, 'Self', pagename) # FIXME
-
-    # FIXME: This is even more crappy
-    def interwikilink(self, on, interwiki='', pagename='', **kw):
-        if not on:
-            return self.url(on,kw)
-
-        wikitag, wikiurl, wikitail, wikitag_bad = wikiutil.resolve_wiki(self.request, '%s:%s' % (interwiki, pagename))
-        wikiurl = wikiutil.mapURL(self.request, wikiurl)
-        href = wikiutil.join_wiki(wikiurl, wikitail)
-
-        return self.url(on, href)
-            
-    def url(self, on, url=None, css=None, **kw):
-        return self._handleNode("ulink", on, (('url', url), ))
-
-    def anchordef(self, name):
-        self._handleNode("anchor", True, (('id', name), ))
-        self._handleNode("ulink", False)
-        return ""
-
-    def anchorlink(self, on, name='', **kw):
-        id = kw.get('id',None)
-        attrs = []
-        if name != '':
-            attrs.append(('endterm', name))
-        if id != None:
-            attrs.append(('linkend', id))
-        elif name != '':
-            attrs.append(('linkend', name))
-
-        return self._handleNode("link", on, attrs)
-
-### Attachments ######################################################
-
-    def attachment_link(self, url, text, **kw):
-        _ = self.request.getText
-        pagename, filename = AttachFile.absoluteName(url, self.page.page_name)
-        fname = wikiutil.taintfilename(filename)
-        fpath = AttachFile.getFilename(self.request, pagename, fname)
-        target = AttachFile.getAttachUrl(pagename, filename, self.request)
-        if not os.path.exists(fpath):
-            return self.text("[attachment:%s]" % url)
-        else:
-            return (self.url(1, target, title="attachment:%s" % url) +
-                    self.text(text) +
-                    self.url(0))
-
-    def attachment_image(self, url, **kw):
-        _ = self.request.getText
-        pagename, filename = AttachFile.absoluteName(url, self.page.page_name)
-        fname = wikiutil.taintfilename(filename)
-        fpath = AttachFile.getFilename(self.request, pagename, fname)
-        if not os.path.exists(fpath):
-            return self.text("[attachment:%s]" % url)
-        else:
-            return self.image(
-                title="attachment:%s" % url,
-                src=AttachFile.getAttachUrl(pagename, filename,
-                                            self.request, addts=1))
-
-    def attachment_drawing(self, url, text, **kw):
-        _ = self.request.getText
-        pagename, filename = AttachFile.absoluteName(url, self.page.page_name)
-        fname = wikiutil.taintfilename(filename)
-        drawing = fname
-        fname = fname + ".png"
-        filename = filename + ".png"
-        if not os.path.exists(fpath):
-            return self.text("[drawing:%s]" % url)
-        else:
-            return self.image(
-                alt=drawing,
-                src=AttachFile.getAttachUrl(pagename, filename, self.request,
-                                            addts=1),
-                html_class="drawing")
-
-### Images and Smileys ##############################################
-
-    def image(self, src=None, **kw):
-        if src:
-            kw['src'] = src
-        media = self.doc.createElement('inlinemediaobject')
-
-        imagewrap = self.doc.createElement('imageobject')
-        media.appendChild(imagewrap)
-
-        image = self.doc.createElement('imagedata')
-        if kw.has_key('src'):
-            image.setAttribute('fileref', kw['src'])
-        if kw.has_key('width'):
-            image.setAttribute('width', kw['width'])
-        if kw.has_key('height'):
-            image.setAttribute('depth', kw['height'])
-        imagewrap.appendChild(image)
-
-        title = ''
-        for a in ('title', 'html_title', 'alt', 'html_alt'):
-            if kw.has_key(a):
-                title = kw[a]
-                break
-        if title:
-            txtcontainer = self.doc.createElement('textobject')
-            media.appendChild(txtcontainer)        
-            txtphrase = self.doc.createElement('phrase')
-            txtphrase.appendChild(self.doc.createTextNode(title))
-            txtcontainer.appendChild(txtphrase)        
-        
-        self.cur.appendChild(media)
-        return ""        
- 
-    def smiley(self, text):
-        w, h, b, img = config.smileys[text.strip()]
-        href = img
-        if not href.startswith('/'):
-            href = self.request.theme.img_url(img)
-        return self.image(src=href, alt=text, width=str(w), height=str(h))
-
-    def icon(self, type):
-        return '' # self.request.theme.make_icon(type)
-
-### Tables ##########################################################
-
-    #FIXME: We should copy code from text_html.py for attr handling
-
-    def table(self, on, attrs=None, **kw):
-        sanitized_attrs = []
-        if attrs and attrs.has_key('id'):
-            sanitized_attrs[id] = attrs['id']
-
-        self._handleNode("table", on, sanitized_attrs)
-        if on:
-            self._addEmptyNode("caption") #dtd for table requires caption		
-        self._handleNode("tgroup", on)
-        self._handleNode("tbody", on)
-        return ""
-    
-    def table_row(self, on, attrs=None, **kw):
-        self.table_current_row_cells = 0
-        sanitized_attrs = []
-        if attrs and attrs.has_key('id'):
-            sanitized_attrs[id] = attrs['id']
-        return self._handleNode("row", on, sanitized_attrs)
-
-    def table_cell(self, on, attrs=None, **kw):
-        # Finish row definition
-        sanitized_attrs = []
-        if attrs and attrs.has_key('id'):
-            sanitized_attrs[id] = attrs['id']
-        # Get number of newly added columns
-        startCount = self.table_current_row_cells
-        addedCellsCount = self._getTableCellCount(attrs)
-        self.table_current_row_cells += addedCellsCount
-        ret = self._handleNode("entry", on, sanitized_attrs)
-        if self.cur.parentNode == self.cur.parentNode.parentNode.firstChild:
-            self._addTableCellDefinition(attrs)
-        # Set cell join if any
-        if addedCellsCount > 1:
-            startString = "xxx" + str(startCount)
-            stopString = "xxx" + str(startCount + addedCellsCount - 1)
-            self.cur.setAttribute("namest", startString)
-            self.cur.setAttribute("nameend", stopString)
-        return ret
-
-### Code ############################################################
-
-    def code_area(self, on, code_id, code_type='code', show=0, start=-1, step=-1):
-        show = show and 'numbered' or 'unnumbered'
-        if start < 1:
-            start = 1
-        
-        attrs = (('id', code_id),
-                ('linenumbering', show),
-                ('startinglinenumber', str(start)),
-                ('language', code_type),
-                ('format','linespecific'),
-                )
-        return self._handleFormatting("screen", on, attrs)
-
-    def code_line(self, on):
-        return '' # No clue why something should be done here
-
-    def code_token(self, on, tok_type):
-        toks_map = {'ID':'methodname',
-                    'Operator':'',
-                    'Char':'',
-                    'Comment':'lineannotation',
-                    'Number':'',
-                    'String':'phrase',
-                    'SPChar':'',
-                    'ResWord':'token',
-                    'ConsWord':'symbol',
-                    'Error':'errortext',
-                    'ResWord2':'',
-                    'Special':'',
-                    'Preprc':'',
-                    'Text':''}
-        if toks_map.has_key(tok_type) and toks_map[tok_type] != '':
-            return self._handleFormatting(toks_map[tok_type], on)
-        else:
-            return ""
-
-    def macro(self, macro_obj, name, args):
-        if name == "TableOfContents":
-            # Table of content can be inserted in docbook transformation
-            return u""
-        # output of all macros is added as the text node
-        # At the begining text mode contain some string which is later
-        # exchange for real value. There is problem that data inserted
-        # as text mode are encoded to xml, e.g. < is encoded in the output as &lt;
-        text = FormatterBase.macro(self, macro_obj, name, args)
-        if len(text) > 0:
-            # prepare identificator
-            sKey = "EXCHANGESTRINGMACRO-" + str(len(self.exchangeKeys)) + "-EXCHANGESTRINGMACRO"
-            self.exchangeKeys.append(sKey)
-            self.exchangeValues.append(text)
-            # append data to lists
-            self.text(sKey)
-        return u""
-
-### Not supported ###################################################
-
-    def rule(self, size = 0, **kw):
-        return ""
-
-    def small(self, on, **kw):
-        return ""
-
-    def big(self, on, **kw):
-        return ""
-
--- a/MoinMoin/i18n/POTFILES.in	Tue May 16 11:44:24 2006 +1200
+++ b/MoinMoin/i18n/POTFILES.in	Wed May 17 09:27:26 2006 +1200
@@ -5,7 +5,6 @@
 caching.py
 config.py
 error.py
-request.py
 search.py
 security.py
 user.py
@@ -13,9 +12,6 @@
 version.py
 wikiacl.py
 wikiform.py
-wikimacro.py
-wikirpc.py
-wikitest.py
 wikiutil.py
 wikidicts.py
 failure.py
@@ -23,8 +19,8 @@
 PageEditor.py
 packages.py
 multiconfig.py
-wikiaction.py
 
+action/__init__.py
 action/PackagePages.py
 action/login.py
 action/LikePages.py
@@ -32,7 +28,6 @@
 action/MyPages.py
 action/RenamePage.py
 action/SpellCheck.py
-action/__init__.py
 action/fckdialog.py
 action/fullsearch.py
 action/links.py
@@ -49,17 +44,16 @@
 action/userprefs.py
 
 converter/__init__.py
-converter/text_html_text_x_moin.py
+converter/text_html_text_moin_wiki.py
 
 formatter/__init__.py
-formatter/base.py
+formatter/pagelinks.py
 formatter/dom_xml.py
 formatter/text_plain.py
 formatter/text_html.py
 formatter/text_xml.py
-formatter/xml_docbook.py
+formatter/text_docbook.py
 formatter/text_gedit.py
-formatter/pagelinks.py
 formatter/text_python.py
 
 i18n/__init__.py
@@ -70,7 +64,7 @@
 logfile/eventlog.py
 logfile/logfile.py
 
-
+macro/__init__.py
 macro/AbandonedPages.py
 macro/Action.py
 macro/AttachInfo.py
@@ -99,25 +93,22 @@
 macro/TeudView.py
 macro/Verbatim.py
 macro/WantedPages.py
-macro/__init__.py
 macro/StatsChart.py
 macro/Include.py
 macro/ShowSmileys.py
 
-parser/CSV.py
 parser/__init__.py
-parser/cplusplus.py
-parser/docbook.py
-parser/irc.py
-parser/java.py
-parser/pascal.py
-parser/plain.py
-parser/python.py
-parser/rst.py
-parser/wiki.py
-parser/xslt.py
-
-processor/__init__.py
+parser/text.py
+parser/text_csv.py
+parser/text_cplusplus.py
+parser/text_docbook.py
+parser/text_irssi.py
+parser/text_java.py
+parser/text_pascal.py
+parser/text_python.py
+parser/text_rst.py
+parser/text_moin_wiki.py
+parser/text_xslt.py
 
 server/__init__.py
 server/daemon.py
@@ -176,9 +167,9 @@
 wikixml/util.py
 wikixml/xsltutil.py
 
+xmlrpc/__init__.py
 xmlrpc/HelloWorld.py
 xmlrpc/UpdateGroup.py
-xmlrpc/__init__.py
 xmlrpc/putClientInfo.py
 xmlrpc/WhoAmI.py
 
@@ -200,3 +191,14 @@
 filter/application_vnd_sun_xml_writer.py
 filter/application_octet_stream.py
 
+request/__init__.py
+request/CGI.py
+request/FCGI.py
+request/CLI.py
+request/WSGI.py
+request/MODPYTHON.py
+request/TWISTED.py
+request/STANDALONE.py
+
+script/moin.py
+
--- a/MoinMoin/i18n/__init__.py	Tue May 16 11:44:24 2006 +1200
+++ b/MoinMoin/i18n/__init__.py	Wed May 17 09:27:26 2006 +1200
@@ -74,14 +74,14 @@
         pass
     currentStack.append(text)
 
-    from MoinMoin.parser.wiki import Parser
+    from MoinMoin.parser.text_moin_wiki import Parser as WikiParser
     from MoinMoin.formatter.text_html import Formatter
     import StringIO
 
     origtext = text
     out = StringIO.StringIO()
     request.redirect(out)
-    parser = Parser(text, request, line_anchors=False)
+    parser = WikiParser(text, request, line_anchors=False)
     formatter = Formatter(request, terse=True)
     reqformatter = None
     if hasattr(request, 'formatter'):
--- a/MoinMoin/macro/FootNote.py	Tue May 16 11:44:24 2006 +1200
+++ b/MoinMoin/macro/FootNote.py	Wed May 17 09:27:26 2006 +1200
@@ -11,7 +11,7 @@
 
 import sha, StringIO
 from MoinMoin import config
-from MoinMoin.parser import wiki
+from MoinMoin.parser.text_moin_wiki import Parser as WikiParser
 
 Dependencies = ["time"] # footnote macro cannot be cached
 
@@ -61,7 +61,7 @@
                         
             out=StringIO.StringIO()
             request.redirect(out)
-            parser=wiki.Parser(request.footnotes[idx][0], request,
+            parser = WikiParser(request.footnotes[idx][0], request,
                                line_anchors=False)
             parser.format(formatter)
             result.append(out.getvalue())
--- a/MoinMoin/macro/__init__.py	Tue May 16 11:44:24 2006 +1200
+++ b/MoinMoin/macro/__init__.py	Wed May 17 09:27:26 2006 +1200
@@ -2,8 +2,8 @@
 """
     MoinMoin - Macro Implementation
 
-    These macros are used by the parser/wiki.py module
-    to implement complex and/or dynamic page content.
+    These macros are used by the wiki parser module to implement complex
+    and/or dynamic page content.
 
     The canonical interface to plugin macros is their execute() function,
     which gets passed an instance of the Macro class. Such an instance
--- a/MoinMoin/multiconfig.py	Tue May 16 11:44:24 2006 +1200
+++ b/MoinMoin/multiconfig.py	Wed May 17 09:27:26 2006 +1200
@@ -309,7 +309,7 @@
         'unsubscribe': ("%(q_page_name)s?action=subscribe", _("UnSubscribe"), "unsubscribe"),
         'subscribe':   ("%(q_page_name)s?action=subscribe", _("Subscribe"), "subscribe"),
         'raw':         ("%(q_page_name)s?action=raw", _("Raw"), "raw"),
-        'xml':         ("%(q_page_name)s?action=format&amp;mimetype=text/xml", _("XML"), "xml"),
+        'xml':         ("%(q_page_name)s?action=show&amp;mimetype=text/xml", _("XML"), "xml"),
         'print':       ("%(q_page_name)s?action=print", _("Print"), "print"),
         'view':        ("%(q_page_name)s", _("View"), "view"),
         'up':          ("%(q_page_parent_page)s", _("Up"), "up"),
@@ -470,7 +470,7 @@
         self._check_directories()
 
         if not isinstance(self.superuser, list):
-            msg = """The superuser</b> setting in your wiki configuration is not a list
+            msg = """The superuser setting in your wiki configuration is not a list
                      (e.g. ['Sample User', 'AnotherUser']).
                      Please change it in your wiki configuration and try again."""
             raise error.ConfigurationError(msg)
--- a/MoinMoin/parser/CSV.py	Tue May 16 11:44:24 2006 +1200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - Parser for CSV data
-
-    This parser lacks to flexibility to read arbitary csv dialects.
-
-    Perhaps this should be rewritten using another CSV lib
-    because the standard module csv does not support unicode.
-
-    @copyright: 2004 by Oliver Graf <ograf@bitart.de>, Alexander Schremmer
-    @license: GNU GPL, see COPYING for details.
-"""
-
-Dependencies = []
-
-class Parser:
-    """ Format CSV data as table
-    """
-
-    extensions = ['.csv']
-    Dependencies = []
-
-    def __init__(self, raw, request, **kw):
-        """ Store the source text.
-        """
-        self.raw = raw
-        self.request = request
-        self.form = request.form
-        self._ = request.getText
-
-        # parse extra arguments for excludes
-        self.exclude = []
-        self.separator = ';'
-        for arg in kw.get('format_args','').split():
-            if arg[0] == '-':
-                try:
-                    idx = int(arg[1:])
-                except ValueError:
-                    pass
-                else:
-                    self.exclude.append(idx-1)
-            else:
-                self.separator = arg
-
-    def format(self, formatter):
-        """ Parse and send the table.
-        """
-        lines = self.raw.split('\n')
-        if lines[0]:
-            # expect column headers in first line
-            first = 1
-        else:
-            # empty first line, no bold headers
-            first = 0
-            del lines[0]
-
-        self.request.write(formatter.table(1))
-        for line in lines:
-            self.request.write(formatter.table_row(1))
-            cells = line.split(self.separator)
-            for idx in range(len(cells)):
-                if idx in self.exclude:
-                    continue
-                self.request.write(formatter.table_cell(1))
-                if first:
-                    self.request.write(formatter.strong(1))
-                self.request.write(formatter.text(cells[idx]))
-                if first:
-                    self.request.write(formatter.strong(0))
-                self.request.write(formatter.table_cell(0))
-            self.request.write(formatter.table_row(0))
-            first = 0
-        self.request.write(formatter.table(0))
-
--- a/MoinMoin/parser/cplusplus.py	Tue May 16 11:44:24 2006 +1200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-	MoinMoin - C++ Source Parser
-
-    @copyright: 2002 by Taesu Pyo <bigflood@hitel.net>
-    @license: GNU GPL, see COPYING for details.
-
-css:
-
-pre.cpparea     { font-style: sans-serif; color: #000000; }
-
-pre.cpparea span.ID       { color: #000000; }
-pre.cpparea span.Char     { color: #004080; }
-pre.cpparea span.Comment  { color: #808080; }
-pre.cpparea span.Number   { color: #008080; font-weight: bold; }
-pre.cpparea span.String   { color: #004080; }
-pre.cpparea span.SPChar   { color: #0000C0; }
-pre.cpparea span.ResWord  { color: #4040ff; font-weight: bold; }
-pre.cpparea span.ConsWord { color: #008080; font-weight: bold; }
-pre.cpparea span.ResWord2 { color: #0080ff; font-weight: bold; }
-pre.cpparea span.Special  { color: #0000ff; }
-pre.cpparea span.Preprc   { color: #804000; }
-
-"""
-
-from MoinMoin.util.ParserBase import ParserBase
-
-Dependencies = []
-
-class Parser(ParserBase):
-
-    parsername = "ColorizedCPlusPlus"
-    extensions = ['.c', '.h', '.cpp', '.c++']
-    Dependencies = []
-    
-    def setupRules(self):
-        ParserBase.setupRules(self)
-
-        self.addRulePair("Comment","/[*]","[*]/")
-        self.addRule("Comment","//.*$")
-        self.addRulePair("String",'L?"',r'$|[^\\](\\\\)*"')
-        self.addRule("Char",r"'\\.'|'[^\\]'")
-        self.addRule("Number",r"[0-9](\.[0-9]*)?(eE[+-][0-9])?[flFLdD]?|0[xX][0-9a-fA-F]+[Ll]?")
-        self.addRule("Preprc",r"^\s*#(.*\\\n)*(.*(?!\\))$")
-        self.addRule("ID","[a-zA-Z_][0-9a-zA-Z_]*")
-        self.addRule("SPChar",r"[~!%^&*()+=|\[\]:;,.<>/?{}-]")
-
-        reserved_words = ['struct','class','union','enum',
-        'int','float','double','signed','unsigned','char','short','void','bool',
-        'long','register','auto','operator',
-        'static','const','private','public','protected','virtual','explicit',
-        'new','delete','this',
-        'if','else','while','for','do','switch','case','default','sizeof',
-        'dynamic_cast','static_cast','const_cast','reinterpret_cast','typeid',
-        'try','catch','throw','throws','return','continue','break','goto']
-
-        reserved_words2 = ['extern', 'volatile', 'typedef', 'friend',
-                           '__declspec', 'inline','__asm','thread','naked',
-                           'dllimport','dllexport','namespace','using',
-                           'template','typename','goto']
-
-        special_words = ['std','string','vector','map','set','cout','cin','cerr']
-        constant_words = ['true','false','NULL']
-
-        self.addReserved(reserved_words)
-        self.addConstant(constant_words)
-
-        self.addWords(reserved_words2,'ResWord2')
-        self.addWords(special_words,'Special')
-
--- a/MoinMoin/parser/docbook.py	Tue May 16 11:44:24 2006 +1200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,197 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - DocBook-XML Parser
-
-    This code was tested with 4Suite 1.0a4 and 1.0b1
-
-    @copyright: 2005 by Henry Ho <henryho167 AT hotmail DOT com>
-    @copyright: 2005 by MoinMoin:AlexanderSchremmer
-    @license: GNU GPL, see COPYING for details.
-
-    DOCBOOK Parser:
-
-    Features:
-    - image support through Attachment
-    - internal Wikilinks if a word is a strict wikiname
-    - image alt is perserved
-    - works with compiled xslt stylesheet for optimized performance
-
-    Configuration:
-    - make sure you have installed the DocBook XSLT files
-    - set the path to the html directory of the DocBook XSLT files in your
-      wiki or farm configuration:
-      docbook_html_dir = r"/usr/share/xml/docbook/stylesheet/nwalsh/html/"
-      Note that this directory needs to be writable because a cache file will
-      be created there.
-
-    >How can I use Ft API for DTD validation?
-    If you have PyXMl installed, you can use ValidatingReader rather than
-    NonvalidatingReader.  See:
-    http://uche.ogbuji.net/tech/akara/nodes/2003-01-01/domlettes
-"""
-
-import StringIO
-import os.path
-import cPickle
-import re
-
-from MoinMoin import caching, config, wikiutil, Page
-from MoinMoin.parser.xslt import Parser as XsltParser
-from MoinMoin.parser.wiki import Parser as WikiParser
-
-Dependencies = []
-
-class Parser(XsltParser):
-    """
-        Send XML file formatted via XSLT.
-    """
-
-    caching = 1
-    Dependencies = Dependencies
-
-    def __init__(self, raw, request, **kw):
-        XsltParser.__init__(self, raw, request)
-
-        # relative path to docbook.xsl and compiled_xsl
-        docbook_html_directory = request.cfg.docbook_html_dir
-        self.db_xsl = os.path.join(docbook_html_directory, 'docbook.xsl')
-        self.db_compiled_xsl = os.path.join(docbook_html_directory, 'db_compiled.dat')
-
-        self.wikiParser = WikiParser(raw = self.raw, request = self.request, pretty_url=1)
-        self.key = 'docbook'
-
-    def format(self, formatter):
-        self.wikiParser.formatter = formatter
-        XsltParser.format(self, formatter)
-
-    def append_stylesheet(self):
-        """"
-            virtual function, for docbook parser
-        """
-        abs_db_xsl = os.path.abspath(self.db_xsl)
-        abs_db_compiled_xsl = os.path.abspath(self.db_compiled_xsl)
-
-        # same as path.exists, but also test if it is a file
-        if not os.path.isfile(abs_db_compiled_xsl):
-            _compile_xsl(abs_db_xsl, abs_db_compiled_xsl)
-
-        assert os.path.isfile(abs_db_compiled_xsl)
-
-        self.processor.appendStylesheetInstance(cPickle.load(file(abs_db_compiled_xsl, 'rb')))
-
-    def parse_result(self, result):
-        """
-        additional parsing to the resulting XSLT'ed result (resultString) before saving
-
-        will do:
-            BASIC CLEAN UP   : remove unnecessary HTML tags
-            RESOLVE IMG SRC  : fix src to find attachment
-            RESOLVE WikiNames: if a word is a valid wikiname & a valid wikipage,
-                               replace word with hyperlink
-        """
-
-        # BASIC CLEAN UP
-        # remove from beginning until end of body tag
-        found = re.search('<body.*?>', result)
-        if found:
-            result = result[found.end():]
-
-        # remove everything after & including </body>
-        found = result.rfind('</body>')
-        if found != -1:
-            result = result[:found]
-
-        # RESOLVE IMG SRC
-        found = re.finditer('<img.*?>', result)
-        if found:
-            splitResult = _splitResult(found, result)
-            for index in range(len(splitResult)):
-                if splitResult[index].startswith('<img'):
-                    found = re.search('src="(?P<source>.*?)"', splitResult[index])
-                    imageSrc = found.group('source')
-                    imageAlt = None # save alt
-                    found = re.search('alt="(?P<alt>.*?)"', splitResult[index])
-                    if found:
-                        imageAlt = found.group('alt')
-                    splitResult[index] = self.wikiParser.attachment( ('attachment:' + imageSrc, "") )
-                    if imageAlt: # restore alt
-                        splitResult[index] = re.sub('alt=".*?"', 'alt="%s"' % imageAlt, splitResult[index])
-
-            result = ''.join(splitResult)
-
-
-        # RESOLVE WikiNames
-        #    if a word is a valid wikiname & a valid wikipage,
-        #    replace word with hyperlink
-
-        found = re.finditer(self.wikiParser.word_rule, result)
-        if found:
-            splitResult = _splitResult(found, result)
-
-            for index in range(len(splitResult)):
-                if (re.match(self.wikiParser.word_rule, splitResult[index])
-                    and Page.Page(self.request, splitResult[index]).exists()):
-                    splitResult[index] = self.wikiParser._word_repl(splitResult[index])
-            result = ''.join(splitResult)
-
-        # remove stuff that fail HTML 4.01 Strict verification
-
-        # remove unsupported attributes
-        result = re.sub(' target=".*?"| type=".*?"', '', result)
-        result = re.sub('<hr .*?>', '<hr>', result)
-
-        # remove <p>...</p> inside <a>...</a> or <caption>...</caption>
-        found = re.finditer('<a href=".*?</a>|<caption>.*?</caption>', result) # XXX re.DOTALL)
-        if found:
-            splitResult = _splitResult(found, result)
-            for index in range(len(splitResult)):
-                if (splitResult[index].startswith('<a href="')
-                    or splitResult[index].startswith('<caption>')):
-                    splitResult[index] = splitResult[index].replace('<p>', '').replace('</p>', '')
-            result = ''.join(splitResult)
-
-        return result
-
-
-
-def _compile_xsl(XSLT_FILE, XSLT_COMPILED_FILE):
-    """
-        compiling docbook stylesheet
-
-        reference: http://155.210.85.193:8010/ccia/nodes/2005-03-18/compileXslt?xslt=/akara/akara.xslt
-    """
-    from Ft.Xml.Xslt.Processor import Processor
-    from Ft.Xml.Xslt import Stylesheet
-    from Ft.Xml import InputSource
-    from Ft.Lib import Uri
-
-    # New docbook processor
-    db_processor=Processor()
-
-    # Docbook Stylesheet
-    my_sheet_uri = Uri.OsPathToUri(XSLT_FILE, 1)
-    sty_isrc = InputSource.DefaultFactory.fromUri(my_sheet_uri)
-
-    # Append Stylesheet
-    db_processor.appendStylesheet(sty_isrc)
-
-    # Pickled stylesheet will be self.abs_db_compiled_xsl file
-    db_root = db_processor.stylesheet.root
-    fw = file(XSLT_COMPILED_FILE, 'wb')
-    cPickle.dump(db_root, fw) # , protocol=2)
-    fw.close()
-
-
-def _splitResult(iterator, result):
-    startpos = 0
-    splitResult = []
-
-    for f in iterator:
-        start, end = f.span()
-        splitResult.append(result[startpos:start])
-        splitResult.append(result[start:end])
-        startpos = end
-    splitResult.append(result[startpos:])
-
-    return splitResult
-
--- a/MoinMoin/parser/irc.py	Tue May 16 11:44:24 2006 +1200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - IRC Log Parser (irssi style logs)
-
-    @copyright: 2004 by Thomas Waldmann
-    @license: GNU GPL, see COPYING for details.
-"""
-
-import re
-from MoinMoin import wikiutil
-
-Dependencies = []
-
-class Parser:
-    """
-        Send IRC logs in a table
-    """
-    extensions = ['.irc']
-    Dependencies = []
-
-    def __init__(self, raw, request, **kw):
-        self.raw = raw
-        self.request = request
-        self.form = request.form
-        self._ = request.getText
-        self.out = kw.get('out', request)
-
-    def format(self, formatter):
-        lines = self.raw.split('\n')
-        # TODO: Add support for displaying things like join and part messages.
-        pattern = re.compile(r"""
-            ((\[|\()?                      # Opening bracket for the timestamp (if it exists)
-                (?P<time>([\d]?\d[:.]?)+)  # Timestamp as one or more :/.-separated groups of 1 or 2 digits (if it exists)
-            (\]|\))?\s+)?                  # Closing bracket for the timestamp (if it exists) plus whitespace
-            <\s*?(?P<nick>.*?)\s*?>        # Nick
-            \s+                            # Space between the nick and message
-            (?P<msg>.*)                    # Message
-        """, re.VERBOSE + re.UNICODE)
-        self.out.write(formatter.table(1))
-        for line in lines:
-            match = pattern.match(line)
-            if match:
-                self.out.write(formatter.table_row(1))
-                for g in ('time', 'nick', 'msg'):
-                    self.out.write(formatter.table_cell(1))
-                    self.out.write(formatter.text(match.group(g) or ''))
-                    self.out.write(formatter.table_cell(0))
-                self.out.write(formatter.table_row(0))
-        self.out.write(formatter.table(0))
-
--- a/MoinMoin/parser/java.py	Tue May 16 11:44:24 2006 +1200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-	MoinMoin - Java Source Parser
-
-    @copyright: 2002 by Taesu Pyo <bigflood@hitel.net>
-    @license: GNU GPL, see COPYING for details.
-
-"""
-
-from MoinMoin.util.ParserBase import ParserBase
-
-Dependencies = []
-
-class Parser(ParserBase):
-
-    parsername = "ColorizedJava"
-    extensions = ['.java']
-    Dependencies = []
-
-    def setupRules(self):
-        ParserBase.setupRules(self)
-
-        self.addRulePair("Comment","/[*]","[*]/")
-        self.addRule("Comment","//.*$")
-        self.addRulePair("String",'"',r'$|[^\\](\\\\)*"')
-        self.addRule("Char",r"'\\.'|'[^\\]'")
-        self.addRule("Number",r"[0-9](\.[0-9]*)?(eE[+-][0-9])?[flFLdD]?|0[xX][0-9a-fA-F]+[Ll]?")
-        self.addRule("ID","[a-zA-Z_][0-9a-zA-Z_]*")
-        self.addRule("SPChar",r"[~!%^&*()+=|\[\]:;,.<>/?{}-]")
-
-        reserved_words = ['class','interface','enum','import','package',
-        'byte','int','long','float','double','char','short','void','boolean',
-        'static','final','const','private','public','protected',
-        'new','this','super','abstract','native','synchronized','transient','volatile','strictfp',
-        'extends','implements','if','else','while','for','do','switch','case','default','instanceof',
-        'try','catch','finally','throw','throws','return','continue','break']
-
-        self.addReserved(reserved_words)
-
-        constant_words = ['true','false','null']
-
-        self.addConstant(constant_words)
--- a/MoinMoin/parser/pascal.py	Tue May 16 11:44:24 2006 +1200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-	MoinMoin - Pascal Source Parser
-
-    @copyright: 2004-2005 by Johannes Berg <johannes@sipsolutions.net>
-    @license: GNU GPL, see COPYING for details.
-"""
-
-from MoinMoin.util.ParserBase import ParserBase
-
-Dependencies = []
-
-class Parser(ParserBase):
-
-    parsername = 'ColorizedPascal'
-    extensions = ['.pas']
-    Dependencies = []
-
-    def __init__(self, raw, request, **kw):
-        ParserBase.__init__(self,raw,request,**kw)
-        self._ignore_case = 1
-
-    def setupRules(self):
-        ParserBase.setupRules(self)
-        
-        self.addRulePair("Comment","\(\*","\*\)")
-        self.addRulePair("Comment","\{","\}")
-        self.addRule("Comment","//.*$")
-        self.addRulePair("String",'\'','\'')
-        self.addRule("Char",r"'\\.'|#[a-f0-9][a-f0-9]")
-        self.addRule("Number",r"[0-9](\.[0-9]*)?(eE[+-][0-9])?|\$[0-9a-fA-F]+")
-        self.addRule("ID","[a-zA-Z_][0-9a-zA-Z_]*")
-        self.addRule("SPChar",r"[~!%^&*()+=|\[\]:;,.<>/?{}-]")
-        
-        reserved_words = ['class','interface','set','uses','unit',
-                          'byte','integer','longint','float','double',
-                          'extended','char','shortint','boolean',
-                          'var','const','private','public','protected',
-                          'new','this','super','abstract','native',
-                          'synchronized','transient','volatile','strictfp',
-                          'if','else','while','for','do','case','default',
-                          'try','except','finally','raise','continue','break',
-                          'begin','end','type','class','implementation',
-                          'procedure','function','constructor','destructor']
-        
-        self.addReserved(reserved_words)
-        
-        constant_words = ['true','false','nil']
-        
-        self.addConstant(constant_words)
--- a/MoinMoin/parser/plain.py	Tue May 16 11:44:24 2006 +1200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - Plain Text Parser
-
-    @copyright: 2000, 2001, 2002 by Jürgen Hermann <jh@web.de>
-    @license: GNU GPL, see COPYING for details.
-"""
-
-Dependencies = []
-
-class Parser:
-    """
-        Send plain text in a HTML <pre> element.
-    """
-
-    ## specify extensions willing to handle (for inline:)
-    ## should be a list of extensions including the leading dot
-    ## TODO: remove the leading dot from the extension. This is stupid.
-    #extensions = ['.txt']
-    ## use '*' instead of the list(!) to specify a default parser
-    ## which is used as fallback
-    extensions = '*'
-    Dependencies = []
-    
-    def __init__(self, raw, request, **kw):
-        self.raw = raw
-        self.request = request
-        self.form = request.form
-        self._ = request.getText
-
-    def format(self, formatter):
-        """ Send the text. """
-        self.request.write(formatter.preformatted(1))
-        self.request.write(formatter.text(self.raw.expandtabs()))
-        self.request.write(formatter.preformatted(0))
--- a/MoinMoin/parser/python.py	Tue May 16 11:44:24 2006 +1200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - highlighting Python Source Parser
-
-    @copyright: 2001 by Jürgen Hermann <jh@web.de>
-    @license: GNU GPL, see COPYING for details.
-"""
-
-import StringIO
-import keyword, token, tokenize, sha
-from MoinMoin import config, wikiutil
-from MoinMoin.util.ParserBase import parse_start_step
-
-_KEYWORD = token.NT_OFFSET + 1
-_TEXT    = token.NT_OFFSET + 2
-
-_tokens = {
-    token.NUMBER:       'Number',
-    token.OP:           'Operator',
-    token.STRING:       'String',
-    tokenize.COMMENT:   'Comment',
-    token.NAME:         'ID',
-    token.ERRORTOKEN:   'Error',
-    _KEYWORD:           'ResWord',
-    _TEXT:              'Text',
-}
-
-Dependencies = []
-
-class Parser:
-    """ Send colored python source.
-    """
-
-    extensions = ['.py']
-    Dependencies = []
-
-    def __init__(self, raw, request, **kw):
-        """ Store the source text.
-        """
-        self.raw = raw.expandtabs().rstrip()
-        self.request = request
-        self.form = request.form
-        self._ = request.getText
-
-        self.show_num, self.num_start, self.num_step, attrs = parse_start_step(request, kw.get('format_args',''))
-
-    def format(self, formatter):
-        """ Parse and send the colored source.
-        """
-        # store line offsets in self.lines
-        self.lines = [0, 0]
-        pos = 0
-        while 1:
-            pos = self.raw.find('\n', pos) + 1
-            if not pos: break
-            self.lines.append(pos)
-        self.lines.append(len(self.raw))
-
-        self._code_id = sha.new(self.raw.encode(config.charset)).hexdigest()
-        self.request.write(formatter.code_area(1, self._code_id, 'ColorizedPython', self.show_num, self.num_start, self.num_step))
-        self.formatter = formatter
-        self.request.write(formatter.code_line(1))
-        #len('%d' % (len(self.lines)-1, )))
-        
-        # parse the source and write it
-        self.pos = 0
-        text = StringIO.StringIO(self.raw)
-        try:
-            tokenize.tokenize(text.readline, self)
-        except tokenize.TokenError, ex:
-            msg = ex[0]
-            line = ex[1][0]
-            errmsg = (self.formatter.linebreak() + 
-                      self.formatter.strong(1) + "ERROR: %s" % msg + self.formatter.strong(0) +
-                      self.formatter.linebreak() +
-                      wikiutil.escape(self.raw[self.lines[line]:]))
-            self.request.write(errmsg)
-        self.request.write(self.formatter.code_line(0))
-        self.request.write(formatter.code_area(0, self._code_id))
-
-    def __call__(self, toktype, toktext, (srow,scol), (erow,ecol), line):
-        """ Token handler.
-        """
-        if 0: print "type", toktype, token.tok_name[toktype], "text", toktext, \
-                    "start", srow,scol, "end", erow,ecol, "<br>"
-
-        # calculate new positions
-        oldpos = self.pos
-        newpos = self.lines[srow] + scol
-        self.pos = newpos + len(toktext)
-
-        # handle newlines
-        if toktype in [token.NEWLINE, tokenize.NL]:
-            self.request.write(self.formatter.code_line(0))
-            self.request.write(self.formatter.code_line(1))
-            return
-
-        # send the original whitespace, if needed
-        if newpos > oldpos:
-            self.request.write(self.formatter.text(self.raw[oldpos:newpos]))
-
-        # skip indenting tokens
-        if toktype in [token.INDENT, token.DEDENT]:
-            self.pos = newpos
-            return
-
-        # map token type to a color group
-        if token.LPAR <= toktype and toktype <= token.OP:
-            toktype = token.OP
-        elif toktype == token.NAME and keyword.iskeyword(toktext):
-            toktype = _KEYWORD
-        tokid = _tokens.get(toktype, _tokens[_TEXT])
-
-        # send text
-        first = 1
-        for part in toktext.split('\n'):
-            if not first:
-                self.request.write(self.formatter.code_line(0))
-                self.request.write(self.formatter.code_line(1))
-            else:
-                first = 0
-            self.request.write(self.formatter.code_token(1, tokid) +
-                               self.formatter.text(part) +
-                               self.formatter.code_token(0, tokid))
-
--- a/MoinMoin/parser/rst.py	Tue May 16 11:44:24 2006 +1200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,602 +0,0 @@
-# -*- coding: iso-8859-1 -*-
-"""
-    MoinMoin - ReStructured Text Parser
-
-    @copyright: 2004 by Matthew Gilbert <gilbert AT voxmea DOT net>
-        and by Alexander Schremmer <alex AT alexanderweb DOT de>
-    @license: GNU GPL, see COPYING for details.
-
-    REQUIRES docutils 0.3.10 or later (must be later than December 30th, 2005)
-"""
-
-import re
-import new
-import StringIO
-import __builtin__
-import sys
-
-import types
-import os
-
-# docutils imports are below
-import MoinMoin.parser.wiki
-from MoinMoin.Page import Page
-from MoinMoin.action import AttachFile
-from MoinMoin import wikiutil
-
-Dependencies = [] # this parser just depends on the raw text
-
-# --- make docutils safe by overriding all module-scoped names related to IO ---
-
-# TODO: Add an error message to dummyOpen so that the user knows what they did
-# requested an unsupported feature of docutils in MoinMoin.
-def dummyOpen(x, y=None, z=None): return
-
-class dummyIO(StringIO.StringIO):
-    def __init__(self, destination=None, destination_path=None,
-                 encoding=None, error_handler='', autoclose=1,
-                 handle_io_errors=1, source_path=None):
-        StringIO.StringIO.__init__(self)
-
-class dummyUrllib2:
-    def urlopen(a):
-        return StringIO.StringIO()
-    urlopen = staticmethod(urlopen)
-
-# # # All docutils imports must be contained below here
-try:
-    import docutils
-    from docutils.core import publish_parts
-    from docutils.writers import html4css1
-    from docutils.nodes import reference
-    from docutils.parsers import rst
-    from docutils.parsers.rst import directives, roles
-# # # All docutils imports must be contained above here
-
-    ErrorParser = None # used in the case of missing docutils
-    docutils.io.FileOutput = docutils.io.FileInput = dummyIO
-except ImportError:
-    # we need to workaround this totally broken plugin interface that does
-    # not allow us to raise exceptions
-    class ErrorParser:
-        caching = 0
-        Dependencies = Dependencies # copy dependencies from module-scope
-
-        def __init__(self, raw, request, **kw):
-            self.raw = raw
-            self.request = request
-    
-        def format(self, formatter):
-            _ = self.request.getText
-            from MoinMoin.parser import plain
-            self.request.write(formatter.sysmsg(1) +
-                               formatter.rawHTML(_('Rendering of reStructured text is not possible, ''please'' install docutils.')) +
-                               formatter.sysmsg(0))
-            plain.Parser(self.raw, self.request).format(formatter)
-    
-    # Create a pseudo docutils environment
-    docutils = html4css1 = dummyUrllib2()
-    html4css1.HTMLTranslator = html4css1.Writer = object
-
-def safe_import(name, globals = None, locals = None, fromlist = None):
-    mod = __builtin__.__import__(name, globals, locals, fromlist)
-    if mod:
-        mod.open = dummyOpen
-        mod.urllib2 = dummyUrllib2
-    return mod
-
-# Go through and change all docutils modules to use a dummyOpen and dummyUrllib2
-# module. Also make sure that any docutils imported modules also get the dummy
-# implementations.
-for i in sys.modules.keys():
-    if i.startswith('docutils') and sys.modules[i]:
-        sys.modules[i].open = dummyOpen
-        sys.modules[i].urllib2 = dummyUrllib2
-        sys.modules[i].__import__ = safe_import
-        
-# --- End of dummy-code --------------------------------------------------------
-
-def html_escape_unicode(node):
-    # Find Python function that does this for me. string.encode('ascii',
-    # 'xmlcharrefreplace') only 2.3 and above.
-    for i in node:
-        if ord(i) > 127:
-            node = node.replace(i, '&#%d;' % (ord(i)))
-    return node
-
-class MoinWriter(html4css1.Writer):
-
-    config_section = 'MoinMoin writer'
-    config_section_dependencies = ('writers',)
-
-    #"""Final translated form of `document`."""
-    output = None
-
-    def wiki_resolver(self, node):
-        """
-            Normally an unknown reference would be an error in an reST document.
-            However, this is how new documents are created in the wiki. This
-            passes on unknown references to eventually be handled by
-            MoinMoin.
-        """
-        if hasattr(node, 'indirect_reference_name'):
-            node['refuri'] = node.indirect_reference_name
-        elif (len(node['ids']) != 0):
-            # If the node has an id then it's probably an internal link. Let
-            # docutils generate an error.
-            return False
-        elif node.hasattr('name'):
-            node['refuri'] = node['name']
-        else:
-            node['refuri'] = node['refname']
-        del node['refname']
-        node.resolved = 1
-        self.nodes.append(node)
-        return True
-
-    wiki_resolver.priority = 001
-
-    def __init__(self, formatter, request):
-        html4css1.Writer.__init__(self)
-        self.formatter = formatter
-        self.request = request
-        # Add our wiki unknown_reference_resolver to our list of functions to
-        # run when a target isn't found
-        self.unknown_reference_resolvers = [self.wiki_resolver]
-        # We create a new parser to process MoinMoin wiki style links in the
-        # reST.
-        self.wikiparser = MoinMoin.parser.wiki.Parser('', self.request)
-        self.wikiparser.formatter = self.formatter
-        self.wikiparser.hilite_re = None
-        self.nodes = []
-        # Make sure it's a supported docutils version.
-        required_version = (0, 3, 10)
-        current_version = tuple([int(i) for i in (docutils.__version__.split('.')+['0','0'])[:3]])
-        if current_version < required_version:
-            err = 'ERROR: The installed docutils version is %s;' % ('.'.join([str(i) for i in current_version]))
-            err += ' version %s or later is required.' % ('.'.join([str(i) for i in required_version]))
-            raise RuntimeError, err
-
-    def translate(self):
-        visitor = MoinTranslator(self.document,
-                                 self.formatter,
-                                 self.request,
-                                 self.wikiparser,
-                                 self)
-        self.document.walkabout(visitor)
-        self.visitor = visitor
-        # Docutils 0.5.0 and later require the writer to have the visitor 
-        # attributes.
-        if (hasattr(html4css1.Writer, 'visitor_attributes')):
-            for attr in html4css1.Writer.visitor_attributes:
-                setattr(self, attr, getattr(visitor, attr))
-        self.output = html_escape_unicode(visitor.astext())
-
-class Parser:
-    caching = 1
-    Dependencies = Dependencies # copy dependencies from module-scope
-
-    def __init__(self, raw, request, **kw):
-        self.raw = raw
-        self.request = request
-        self.form = request.form
-
-    def format(self, formatter):
-        # Create our simple parser
-        parser = MoinDirectives(self.request)
-
-        parts = publish_parts(
-            source = self.raw,
-            writer = MoinWriter(formatter, self.request),
-            settings_overrides = {
-                'halt_level': 5,
-                'traceback': True,
-                'file_insertion_enabled': 0,
-                'raw_enabled': 0,
-                'stylesheet_path': '',
-                'template': '',
-            }
-        )
-
-        html = []
-        if parts['title']:
-            html.append(formatter.rawHTML('<h1>%s</h1>' % parts['title']))
-        # If there is only one subtitle then it is held in parts['subtitle'].
-        # However, if there is more than one subtitle then this is empty and
-        # fragment contains all of the subtitles.
-        if parts['subtitle']:
-            html.append(formatter.rawHTML('<h2>%s</h2>' % parts['subtitle']))
-        if parts['docinfo']:
-            html.append(parts['docinfo'])
-        html.append(parts['fragment'])
-        self.request.write(html_escape_unicode('\n'.join(html)))
-
-class RawHTMLList(list):
-    """
-        RawHTMLList catches all html appended to internal HTMLTranslator lists.
-        It passes the HTML through the MoinMoin rawHTML formatter to strip 
-        markup when necessary. This is to support other formatting outputs
-        (such as ?action=format&mimetype=text/plain).
-    """
-    
-    def __init__(self, formatter):
-        self.formatter = formatter
-        
-    def append(self, text):
-        f = sys._getframe()
-        if f.f_back.f_code.co_filename.endswith('html4css1.py'):
-            if isinstance(text, types.StringType) or isinstance(text, types.UnicodeType):
-                text = self.formatter.rawHTML(text)
-        list.append(self, text)
-
-class MoinTranslator(html4css1.HTMLTranslator):
-
-    def __init__(self, document, formatter, request, parser, writer):
-        html4css1.HTMLTranslator.__init__(self, document)
-        self.formatter = formatter
-        self.request = request
-        # Using our own writer when needed. Save the old one to restore
-        # after the page has been processed by the html4css1 parser.
-        self.original_write, self.request.write = self.request.write, self.capture_wiki_formatting
-        self.wikiparser = parser
-        self.wikiparser.request = request
-        # MoinMoin likes to start the initial headers at level 3 and the title
-        # gets level 2, so to comply with their styles, we do here also.
-        # TODO: Could this be fixed by passing this value in settings_overrides?
-        self.initial_header_level = 3
-        # Temporary place for wiki returned markup. This will be filled when
-        # replacing the default writer with the capture_wiki_formatting
-        # function (see visit_image for an example).
-        self.wiki_text = ''
-        self.setup_wiki_handlers()
-        self.setup_admonitions_handlers()
-        
-        # Make all internal lists RawHTMLLists, see RawHTMLList class
-        # comment for more information.
-        for i in self.__dict__:
-            if isinstance(getattr(self, i), types.ListType):
-                setattr(self, i, RawHTMLList(formatter))
-
-    def depart_docinfo(self, node):
-        """
-            depart_docinfo assigns a new list to self.body, we need to re-make that
-            into a RawHTMLList.
-        """
-        html4css1.HTMLTranslator.depart_docinfo(self, node)
-        self.body = RawHTMLList(self.formatter)
-
-    def capture_wiki_formatting(self, text):
-        """
-            Captures MoinMoin generated markup to the instance variable
-            wiki_text.
-        """
-        # For some reason getting empty strings here which of course overwrites
-        # what we really want (this is called multiple times per MoinMoin
-        # format call, which I don't understand).
-        self.wiki_text += text
-
-    def process_wiki_text(self, text):
-        """
-            This sequence is repeated numerous times, so its captured as a
-            single call here. Its important that wiki_text is blanked before we
-            make the format call. format will call request.write which we've
-            hooked to capture_wiki_formatting. If wiki_text is not blanked
-            before a call to request.write we will get the old markup as well as
-            the newly generated markup.
-
-            TODO: Could implement this as a list so that it acts as a stack. I
-            don't like having to remember to blank wiki_text.
-        """
-        self.wiki_text = ''
-        self.wikiparser.raw = text
-        self.wikiparser.format(self.formatter)
-
-    def add_wiki_markup(self):
-        """
-            Place holder in case this becomes more elaborate someday. For now it
-            only appends the MoinMoin generated markup to the html body and
-            raises SkipNode.
-        """
-        self.body.append(self.wiki_text)
-        self.wiki_text = ''
-        raise docutils.nodes.SkipNode
-
-    def astext(self):
-        self.request.write = self.original_write
-        return html4css1.HTMLTranslator.astext(self)
-
-    def fixup_wiki_formatting(self, text):
-        replacement = {'<p>': '', '</p>': '', '\n': '', '> ': '>'}
-        for src, dst in replacement.items():
-            text = text.replace(src, dst)
-        # Everything seems to have a space ending the text block. We want to
-        # get rid of this
-        if text and text[-1] == ' ':
-            text = text[:-1]
-        return text
-
-    def visit_reference(self, node):
-        """
-            Pass links to MoinMoin to get the correct wiki space url. Extract
-            the url and pass it on to the html4css1 writer to handle. Inline
-            images are also handled by visit_image. Not sure what the "drawing:"
-            link scheme is used for, so for now it is handled here.
-
-            Also included here is a hack to allow MoinMoin macros. This routine
-            checks for a link which starts with "[[". This link is passed to the
-            MoinMoin formatter and the resulting markup is inserted into the
-            document in the place of the original link reference.
-        """
-        if 'refuri' in node.attributes:
-            refuri = node['refuri']
-            prefix = ''
-            link = refuri
-            if ':' in refuri:
-                prefix, link = refuri.lstrip().split(':', 1)
-            
-            # First see if MoinMoin should handle completely. Exits through add_wiki_markup.
-            if ((refuri.startswith('[[') and refuri.endswith(']]')) or 
-                    (prefix == 'drawing') or
-                    (prefix == 'inline')):
-                self.process_wiki_text(refuri)
-                # Don't call fixup_wiki_formatting because who knows what
-                # MoinMoin is inserting. (exits through add_wiki_markup)
-                self.add_wiki_markup()
-
-            # From here down, all links are handled by docutils (except 
-            # missing attachments), just fixup node['refuri'].
-            if prefix == 'attachment':
-                attach_file = AttachFile.getFilename(self.request, 
-                        self.request.page.page_name, link)
-                if not os.path.exists(attach_file):
-                    # Attachment doesn't exist, give to MoinMoin to insert
-                    # upload text.
-                    self.process_wiki_text(refuri)
-                    self.add_wiki_markup()
-                # Attachment exists, just get a link to it.
-                node['refuri'] = AttachFile.getAttachUrl(self.request.page.page_name, 
-                        link, self.request)
-                if not [i for i in node.children if i.__class__ == docutils.nodes.image]:
-                    node['classes'].append(prefix)                
-            elif prefix == 'wiki':
-                wikitag, wikiurl, wikitail, err = wikiutil.resolve_wiki(self.request, link)
-                wikiurl = wikiutil.mapURL(self.request, wikiurl)
-                node['refuri'] = wikiutil.join_wiki(wikiurl, wikitail)
-                # Only add additional class information if the reference does
-                # not have a child image (don't want to add additional markup
-                # for images with targets).
-                if not [i for i in node.children if i.__class__ == docutils.nodes.image]:
-                    node['classes'].append('interwiki')
-            elif prefix != '':
-                # Some link scheme (http, file, https, mailto, etc.), add class
-                # information if the reference doesn't have a child image (don't 
-                # want additional markup for images with targets). 
-                # Don't touch the refuri.
-                if not [i for i in node.children if i.__class__ == docutils.nodes.image]:
-                    node['classes'].append(prefix)
-            else:
-                # Default case - make a link to a wiki page.
-                page = MoinMoin.Page.Page(self.request, refuri)
-                node['refuri'] = page.url(self.request)
-                if not page.exists():
-                    node['classes'].append('nonexistent')
-        html4css1.HTMLTranslator.visit_reference(self, node)
-
-    def visit_image(self, node):
-        """
-            Need to intervene in the case of inline images. We need MoinMoin to
-            give us the actual src line to the image and then we can feed this
-            to the default html4css1 writer. NOTE: Since the writer can't "open"
-            this image the scale attribute doesn't work without directly
-            specifying the height or width (or both).
-
-            TODO: Need to handle figures similarly.
-        """
-        uri = node['uri'].lstrip()
-        prefix = ''          # assume no prefix
-        attach_name = uri
-        if ':' in uri:
-            prefix = uri.split(':', 1)[0]
-            attach_name = uri.split(':', 1)[1]
-        # if prefix isn't URL, try to display in page
-        if not prefix.lower() in ('file', 'http', 'https', 'ftp'):
-            attach_file = AttachFile.getFilename(self.request, 
-                    self.request.page.page_name, attach_name)
-            if not os.path.exists(attach_file):
-                # Attachment doesn't exist, MoinMoin should process it
-                if prefix == '':
-                    prefix = 'inline:'
-                self.process_wiki_text(prefix + attach_name)
-                self.wiki_text = self.fixup_wiki_formatting(self.wiki_text)
-                self.add_wiki_markup()
-            # Attachment exists, get a link to it.
-            # create the url
-            node['uri'] = AttachFile.getAttachUrl(self.request.page.page_name, 
-                    attach_name, self.request, addts = 1)
-            if not node.hasattr('alt'):
-                node['alt'] = node.get('name', uri)
-        html4css1.HTMLTranslator.visit_image(self, node)
-
-    def create_wiki_functor(self, moin_func):
-        moin_callable = getattr(self.formatter, moin_func)
-        def visit_func(self, node):
-            self.wiki_text = ''
-            self.request.write(moin_callable(1))
-            self.body.append(self.wiki_text)
-        def depart_func(self, node):
-            self.wiki_text = ''
-            self.request.write(moin_callable(0))
-            self.body.append(self.wiki_text)
-        return visit_func, depart_func
-
-    def setup_wiki_handlers(self):
-        """
-            Have the MoinMoin formatter handle markup when it makes sense. These
-            are portions of the document that do not contain reST specific
-            markup. This allows these portions of the document to look
-            consistent with other wiki pages.
-
-            Setup dispatch routines to handle basic document markup. The
-            hanlders dict is the html4css1 handler name followed by the wiki
-            handler name.
-        """
-        handlers = {
-            # Text Markup
-            'emphasis': 'emphasis',
-            'strong': 'strong',
-            'literal': 'code',
-            # Blocks
-            'literal_block': 'preformatted',
-            # Simple Lists
-            # bullet-lists are handled completely by docutils because it uses
-            # the node context to decide when to make a compact list 
-            # (no <p> tags).
-            'list_item': 'listitem',
-            # Definition List
-            'definition_list': 'definition_list',
-        }
-        for rest_func, moin_func in handlers.items():
-            visit_func, depart_func = self.create_wiki_functor(moin_func)
-            visit_func = new.instancemethod(visit_func, self, MoinTranslator)
-            depart_func = new.instancemethod(depart_func, self, MoinTranslator)
-            setattr(self, 'visit_%s' % (rest_func), visit_func)
-            setattr(self, 'depart_%s' % (rest_func), depart_func)
-
-    # Enumerated list takes an extra paramter so we handle this differently
-    def visit_enumerated_list(self, node):
-        self.wiki_text = ''
-        self.request.write(self.formatter.number_list(1, start=node.get('start', None)))
-        self.body.append(self.wiki_text)
-
-    def depart_enumerated_list(self, node):
-        self.wiki_text = ''
-        self.request.write(self.formatter.number_list(0))
-        self.body.append(self.wiki_text)
-
-    # Admonitions are handled here -=- tmacam
-    def create_admonition_functor(self, admotion_class):
-        tag_class = 'admonition_' + admotion_class
-        def visit_func(self, node):
-            self.wiki_text = ''
-            self.request.write(self.formatter.div(1,
-                                                  attr={'class': tag_class},
-                                                  allowed_attrs=[]))
-            self.body.append(self.wiki_text)
-        def depart_func(self, node):
-            self.wiki_text = ''
-            self.request.write(self.formatter.div(0))
-            self.body.append(self.wiki_text)
-            
-        return visit_func, depart_func 
-
-    def setup_admonitions_handlers(self):
-        """
-            Admonitions are handled here... We basically surround admonitions
-            in a div with class admonition_{name of the admonition}.
-        """
-        handled_admonitions = [
-            'attention',
-            'caution',
-            'danger',
-            'error',
-            'hint',
-            'important',
-            'note',
-            'tip',
-            'warning',
-        ]
-        for adm in handled_admonitions:
-            visit_func, depart_func = self.create_admonition_functor(adm)
-            visit_func = new.instancemethod(visit_func, self, MoinTranslator)
-            depart_func = new.instancemethod(depart_func, self, MoinTranslator)
-            setattr(self, 'visit_%s' % (adm), visit_func)
-            setattr(self, 'depart_%s' % (adm), depart_func)
-
-
-class MoinDirectives:
-    """
-        Class to handle all custom directive handling. This code is called as
-        part of the parsing stage.
-    """
-
-    def __init__(self, request):
-        self.request = request
-
-        # include MoinMoin pages
-        directives.register_directive('include', self.include)
-
-        # used for MoinMoin macros
-        directives.register_directive('macro', self.macro)
-
-        # disallow a few directives in order to prevent XSS
-        # for directive in ('meta', 'include', 'raw'):
-        for directive in ('meta', 'raw'):
-            directives.register_directive(directive, None)
-
-        # disable the raw role
-        roles._roles['raw'] = None
-
-        # As a quick fix for infinite includes we only allow a fixed number of
-        # includes per page
-        self.num_includes = 0
-        self.max_includes = 10
-
-    # Handle the include directive rather than letting the default docutils
-    # parser handle it. This allows the inclusion of MoinMoin pages instead of
-    # something from the filesystem.
-    def include(self, name, arguments, options, content, lineno,
-                content_offset, block_text, state, state_machine):
-        # content contains the included file name
-
-        _ = self.request.getText
-
-        # Limit the number of documents that can be included
-        if self.num_includes < self.max_includes:
-            self.num_includes += 1
-        else:
-            lines = [_("**Maximum number of allowed includes exceeded**")]
-            state_machine.insert_input(lines, 'MoinDirectives')
-            return
-
-        if len(content):
-            page = Page(page_name = content[0], request = self.request)
-            if page.exists():
-                text = page.get_raw_body()
-                lines = text.split('\n')
-                # Remove the "#format rst" line
-                if lines[0].startswith("#format"):
-                    del lines[0]
-            else:
-                lines = [_("**Could not find the referenced page: %s**") % (content[0],)]
-            # Insert the text from the included document and then continue
-            # parsing
-            state_machine.insert_input(lines, 'MoinDirectives')
-        return
-
-    include.content = True
-
-    # Add additional macro directive.
-    # This allows MoinMoin macros to be used either by using the directive
-    # directly or by using the substitution syntax. Much cleaner than using the
-    # reference hack (`[[SomeMacro]]`_). This however simply adds a node to the
-    # document tree which is a reference, but through a much better user
-    # interface.
-    def macro(self, name, arguments, options, content, lineno,
-                content_offset, block_text, state, state_machine):
-        # content contains macro to be called
-        if len(content):
-            # Allow either with or without brackets
-            if content[0].startswith('[['):
-                macro = content[0]
-            else:
-                macro = '[[%s]]' % content[0]
-            ref = reference(macro, refuri = macro)
-            ref['name'] = macro
-            return [ref]
-        return
-
-    macro.content = True
-
-if ErrorParser: # fixup in case of missing docutils
-    Parser = ErrorParser
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/parser/text.py	Wed May 17 09:27:26 2006 +1200
@@ -0,0 +1,35 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - Plain Text Parser, fallback for text/*
+
+    @copyright: 2000, 2001, 2002 by Jürgen Hermann <jh@web.de>
+    @license: GNU GPL, see COPYING for details.
+"""
+
+Dependencies = []
+
+class Parser:
+    """
+        Send plain text in a HTML <pre> element.
+    """
+
+    ## specify extensions willing to handle (for inline:)
+    ## should be a list of extensions including the leading dot
+    ## TODO: remove the leading dot from the extension. This is stupid.
+    #extensions = ['.txt']
+    ## use '*' instead of the list(!) to specify a default parser
+    ## which is used as fallback
+    extensions = '*'
+    Dependencies = []
+    
+    def __init__(self, raw, request, **kw):
+        self.raw = raw
+        self.request = request
+        self.form = request.form
+        self._ = request.getText
+
+    def format(self, formatter):
+        """ Send the text. """
+        self.request.write(formatter.preformatted(1))
+        self.request.write(formatter.text(self.raw.expandtabs()))
+        self.request.write(formatter.preformatted(0))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/parser/text_cplusplus.py	Wed May 17 09:27:26 2006 +1200
@@ -0,0 +1,70 @@
+# -*- coding: iso-8859-1 -*-
+"""
+	MoinMoin - C++ Source Parser
+
+    @copyright: 2002 by Taesu Pyo <bigflood@hitel.net>
+    @license: GNU GPL, see COPYING for details.
+
+css:
+
+pre.cpparea     { font-style: sans-serif; color: #000000; }
+
+pre.cpparea span.ID       { color: #000000; }
+pre.cpparea span.Char     { color: #004080; }
+pre.cpparea span.Comment  { color: #808080; }
+pre.cpparea span.Number   { color: #008080; font-weight: bold; }
+pre.cpparea span.String   { color: #004080; }
+pre.cpparea span.SPChar   { color: #0000C0; }
+pre.cpparea span.ResWord  { color: #4040ff; font-weight: bold; }
+pre.cpparea span.ConsWord { color: #008080; font-weight: bold; }
+pre.cpparea span.ResWord2 { color: #0080ff; font-weight: bold; }
+pre.cpparea span.Special  { color: #0000ff; }
+pre.cpparea span.Preprc   { color: #804000; }
+
+"""
+
+from MoinMoin.util.ParserBase import ParserBase
+
+Dependencies = []
+
+class Parser(ParserBase):
+
+    parsername = "ColorizedCPlusPlus"
+    extensions = ['.c', '.h', '.cpp', '.c++']
+    Dependencies = []
+    
+    def setupRules(self):
+        ParserBase.setupRules(self)
+
+        self.addRulePair("Comment","/[*]","[*]/")
+        self.addRule("Comment","//.*$")
+        self.addRulePair("String",'L?"',r'$|[^\\](\\\\)*"')
+        self.addRule("Char",r"'\\.'|'[^\\]'")
+        self.addRule("Number",r"[0-9](\.[0-9]*)?(eE[+-][0-9])?[flFLdD]?|0[xX][0-9a-fA-F]+[Ll]?")
+        self.addRule("Preprc",r"^\s*#(.*\\\n)*(.*(?!\\))$")
+        self.addRule("ID","[a-zA-Z_][0-9a-zA-Z_]*")
+        self.addRule("SPChar",r"[~!%^&*()+=|\[\]:;,.<>/?{}-]")
+
+        reserved_words = ['struct','class','union','enum',
+        'int','float','double','signed','unsigned','char','short','void','bool',
+        'long','register','auto','operator',
+        'static','const','private','public','protected','virtual','explicit',
+        'new','delete','this',
+        'if','else','while','for','do','switch','case','default','sizeof',
+        'dynamic_cast','static_cast','const_cast','reinterpret_cast','typeid',
+        'try','catch','throw','throws','return','continue','break','goto']
+
+        reserved_words2 = ['extern', 'volatile', 'typedef', 'friend',
+                           '__declspec', 'inline','__asm','thread','naked',
+                           'dllimport','dllexport','namespace','using',
+                           'template','typename','goto']
+
+        special_words = ['std','string','vector','map','set','cout','cin','cerr']
+        constant_words = ['true','false','NULL']
+
+        self.addReserved(reserved_words)
+        self.addConstant(constant_words)
+
+        self.addWords(reserved_words2,'ResWord2')
+        self.addWords(special_words,'Special')
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/parser/text_csv.py	Wed May 17 09:27:26 2006 +1200
@@ -0,0 +1,74 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - Parser for CSV data
+
+    This parser lacks to flexibility to read arbitary csv dialects.
+
+    Perhaps this should be rewritten using another CSV lib
+    because the standard module csv does not support unicode.
+
+    @copyright: 2004 by Oliver Graf <ograf@bitart.de>, Alexander Schremmer
+    @license: GNU GPL, see COPYING for details.
+"""
+
+Dependencies = []
+
+class Parser:
+    """ Format CSV data as table
+    """
+
+    extensions = ['.csv']
+    Dependencies = []
+
+    def __init__(self, raw, request, **kw):
+        """ Store the source text.
+        """
+        self.raw = raw
+        self.request = request
+        self.form = request.form
+        self._ = request.getText
+
+        # parse extra arguments for excludes
+        self.exclude = []
+        self.separator = ';'
+        for arg in kw.get('format_args','').split():
+            if arg[0] == '-':
+                try:
+                    idx = int(arg[1:])
+                except ValueError:
+                    pass
+                else:
+                    self.exclude.append(idx-1)
+            else:
+                self.separator = arg
+
+    def format(self, formatter):
+        """ Parse and send the table.
+        """
+        lines = self.raw.split('\n')
+        if lines[0]:
+            # expect column headers in first line
+            first = 1
+        else:
+            # empty first line, no bold headers
+            first = 0
+            del lines[0]
+
+        self.request.write(formatter.table(1))
+        for line in lines:
+            self.request.write(formatter.table_row(1))
+            cells = line.split(self.separator)
+            for idx in range(len(cells)):
+                if idx in self.exclude:
+                    continue
+                self.request.write(formatter.table_cell(1))
+                if first:
+                    self.request.write(formatter.strong(1))
+                self.request.write(formatter.text(cells[idx]))
+                if first:
+                    self.request.write(formatter.strong(0))
+                self.request.write(formatter.table_cell(0))
+            self.request.write(formatter.table_row(0))
+            first = 0
+        self.request.write(formatter.table(0))
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/parser/text_docbook.py	Wed May 17 09:27:26 2006 +1200
@@ -0,0 +1,197 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - DocBook-XML Parser
+
+    This code was tested with 4Suite 1.0a4 and 1.0b1
+
+    @copyright: 2005 by Henry Ho <henryho167 AT hotmail DOT com>
+    @copyright: 2005 by MoinMoin:AlexanderSchremmer
+    @license: GNU GPL, see COPYING for details.
+
+    DOCBOOK Parser:
+
+    Features:
+    - image support through Attachment
+    - internal Wikilinks if a word is a strict wikiname
+    - image alt is perserved
+    - works with compiled xslt stylesheet for optimized performance
+
+    Configuration:
+    - make sure you have installed the DocBook XSLT files
+    - set the path to the html directory of the DocBook XSLT files in your
+      wiki or farm configuration:
+      docbook_html_dir = r"/usr/share/xml/docbook/stylesheet/nwalsh/html/"
+      Note that this directory needs to be writable because a cache file will
+      be created there.
+
+    >How can I use Ft API for DTD validation?
+    If you have PyXMl installed, you can use ValidatingReader rather than
+    NonvalidatingReader.  See:
+    http://uche.ogbuji.net/tech/akara/nodes/2003-01-01/domlettes
+"""
+
+import StringIO
+import os.path
+import cPickle
+import re
+
+from MoinMoin import caching, config, wikiutil, Page
+from MoinMoin.parser.text_xslt import Parser as XsltParser
+from MoinMoin.parser.text_moin_wiki import Parser as WikiParser
+
+Dependencies = []
+
+class Parser(XsltParser):
+    """
+        Send XML file formatted via XSLT.
+    """
+
+    caching = 1
+    Dependencies = Dependencies
+
+    def __init__(self, raw, request, **kw):
+        XsltParser.__init__(self, raw, request)
+
+        # relative path to docbook.xsl and compiled_xsl
+        docbook_html_directory = request.cfg.docbook_html_dir
+        self.db_xsl = os.path.join(docbook_html_directory, 'docbook.xsl')
+        self.db_compiled_xsl = os.path.join(docbook_html_directory, 'db_compiled.dat')
+
+        self.wikiParser = WikiParser(raw = self.raw, request = self.request, pretty_url=1)
+        self.key = 'docbook'
+
+    def format(self, formatter):
+        self.wikiParser.formatter = formatter
+        XsltParser.format(self, formatter)
+
+    def append_stylesheet(self):
+        """"
+            virtual function, for docbook parser
+        """
+        abs_db_xsl = os.path.abspath(self.db_xsl)
+        abs_db_compiled_xsl = os.path.abspath(self.db_compiled_xsl)
+
+        # same as path.exists, but also test if it is a file
+        if not os.path.isfile(abs_db_compiled_xsl):
+            _compile_xsl(abs_db_xsl, abs_db_compiled_xsl)
+
+        assert os.path.isfile(abs_db_compiled_xsl)
+
+        self.processor.appendStylesheetInstance(cPickle.load(file(abs_db_compiled_xsl, 'rb')))
+
+    def parse_result(self, result):
+        """
+        additional parsing to the resulting XSLT'ed result (resultString) before saving
+
+        will do:
+            BASIC CLEAN UP   : remove unnecessary HTML tags
+            RESOLVE IMG SRC  : fix src to find attachment
+            RESOLVE WikiNames: if a word is a valid wikiname & a valid wikipage,
+                               replace word with hyperlink
+        """
+
+        # BASIC CLEAN UP
+        # remove from beginning until end of body tag
+        found = re.search('<body.*?>', result)
+        if found:
+            result = result[found.end():]
+
+        # remove everything after & including </body>
+        found = result.rfind('</body>')
+        if found != -1:
+            result = result[:found]
+
+        # RESOLVE IMG SRC
+        found = re.finditer('<img.*?>', result)
+        if found:
+            splitResult = _splitResult(found, result)
+            for index in range(len(splitResult)):
+                if splitResult[index].startswith('<img'):
+                    found = re.search('src="(?P<source>.*?)"', splitResult[index])
+                    imageSrc = found.group('source')
+                    imageAlt = None # save alt
+                    found = re.search('alt="(?P<alt>.*?)"', splitResult[index])
+                    if found:
+                        imageAlt = found.group('alt')
+                    splitResult[index] = self.wikiParser.attachment( ('attachment:' + imageSrc, "") )
+                    if imageAlt: # restore alt
+                        splitResult[index] = re.sub('alt=".*?"', 'alt="%s"' % imageAlt, splitResult[index])
+
+            result = ''.join(splitResult)
+
+
+        # RESOLVE WikiNames
+        #    if a word is a valid wikiname & a valid wikipage,
+        #    replace word with hyperlink
+
+        found = re.finditer(self.wikiParser.word_rule, result)
+        if found:
+            splitResult = _splitResult(found, result)
+
+            for index in range(len(splitResult)):
+                if (re.match(self.wikiParser.word_rule, splitResult[index])
+                    and Page.Page(self.request, splitResult[index]).exists()):
+                    splitResult[index] = self.wikiParser._word_repl(splitResult[index])
+            result = ''.join(splitResult)
+
+        # remove stuff that fail HTML 4.01 Strict verification
+
+        # remove unsupported attributes
+        result = re.sub(' target=".*?"| type=".*?"', '', result)
+        result = re.sub('<hr .*?>', '<hr>', result)
+
+        # remove <p>...</p> inside <a>...</a> or <caption>...</caption>
+        found = re.finditer('<a href=".*?</a>|<caption>.*?</caption>', result) # XXX re.DOTALL)
+        if found:
+            splitResult = _splitResult(found, result)
+            for index in range(len(splitResult)):
+                if (splitResult[index].startswith('<a href="')
+                    or splitResult[index].startswith('<caption>')):
+                    splitResult[index] = splitResult[index].replace('<p>', '').replace('</p>', '')
+            result = ''.join(splitResult)
+
+        return result
+
+
+
+def _compile_xsl(XSLT_FILE, XSLT_COMPILED_FILE):
+    """
+        compiling docbook stylesheet
+
+        reference: http://155.210.85.193:8010/ccia/nodes/2005-03-18/compileXslt?xslt=/akara/akara.xslt
+    """
+    from Ft.Xml.Xslt.Processor import Processor
+    from Ft.Xml.Xslt import Stylesheet
+    from Ft.Xml import InputSource
+    from Ft.Lib import Uri
+
+    # New docbook processor
+    db_processor=Processor()
+
+    # Docbook Stylesheet
+    my_sheet_uri = Uri.OsPathToUri(XSLT_FILE, 1)
+    sty_isrc = InputSource.DefaultFactory.fromUri(my_sheet_uri)
+
+    # Append Stylesheet
+    db_processor.appendStylesheet(sty_isrc)
+
+    # Pickled stylesheet will be self.abs_db_compiled_xsl file
+    db_root = db_processor.stylesheet.root
+    fw = file(XSLT_COMPILED_FILE, 'wb')
+    cPickle.dump(db_root, fw) # , protocol=2)
+    fw.close()
+
+
+def _splitResult(iterator, result):
+    startpos = 0
+    splitResult = []
+
+    for f in iterator:
+        start, end = f.span()
+        splitResult.append(result[startpos:start])
+        splitResult.append(result[start:end])
+        startpos = end
+    splitResult.append(result[startpos:])
+
+    return splitResult
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/parser/text_html.py	Wed May 17 09:27:26 2006 +1200
@@ -0,0 +1,34 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - HTML Parser
+
+    @copyright: 2006 by MoinMoin:AlexanderSchremmer
+    @license: GNU GPL, see COPYING for details.
+"""
+
+from MoinMoin.support.htmlmarkup import Markup
+from HTMLParser import HTMLParseError
+
+Dependencies = []
+
+class Parser:
+    """
+        Sends HTML code after filtering it.
+    """
+
+    extensions = ['.htm', '.html']
+    Dependencies = Dependencies
+    
+    def __init__(self, raw, request, **kw):
+        self.raw = raw
+        self.request = request
+
+    def format(self, formatter):
+        """ Send the text. """
+        try:
+            self.request.write(formatter.rawHTML(Markup(self.raw).sanitize()))
+        except HTMLParseError, e:
+            self.request.write(formatter.sysmsg(1) + 
+                formatter.text(u'HTML parsing error: %s in "%s"' % (e.msg,
+                                  self.raw.splitlines()[e.lineno - 1].strip())) +
+                formatter.sysmsg(0))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/parser/text_irssi.py	Wed May 17 09:27:26 2006 +1200
@@ -0,0 +1,50 @@
+# -*- coding: iso-8859-1 -*-
+"""
+    MoinMoin - IRC Log Parser (irssi style logs)
+
+    @copyright: 2004 by Thomas Waldmann<