[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

new trac version to lenny



hello

i would like to ship a new version to lenny if it is still possible.

debdiff attached and the packages are available in
http://alioth.debian.org/~gass-guest/trac .


evaluating the changelog:

* Updated README.Debian about upgrading issues ( Closes: #501338 )

 - users need to upgrade their projects database, when upgrading trac
from etch. that is not written anywhere.
 * Added option to allow python2.5 built in functions of squilite. (
    Closes: #518560 )
 - a small change in debian/control


  * Applied patch to finally install the contrib directory ( Closes:
    #495019 )


this is a removal of a patch and a simple change in debian/rules to
correctly install the contrib directory

  * Raised compat version ( Closes: #497862 )

why not?


please, check if this is ok to go to lenny, thanks.

Luis Matos

diff -u trac-0.11.1/debian/compat trac-0.11.1/debian/compat
--- trac-0.11.1/debian/compat
+++ trac-0.11.1/debian/compat
@@ -1 +1 @@
-4
+6
diff -u trac-0.11.1/debian/rules trac-0.11.1/debian/rules
--- trac-0.11.1/debian/rules
+++ trac-0.11.1/debian/rules
@@ -33,6 +33,7 @@
 	dh_testroot
 	dh_installchangelogs
 	dh_installdocs
+	dh_install
 	dh_installman
 	dh_link
 	dh_lintian
diff -u trac-0.11.1/debian/changelog trac-0.11.1/debian/changelog
--- trac-0.11.1/debian/changelog
+++ trac-0.11.1/debian/changelog
@@ -1,3 +1,14 @@
+trac (0.11.1-2.1lenny1) UNRELEASED; urgency=low
+
+  * Updated README.Debian about upgrading issues ( Closes: #501338 )
+  * Added option to allow python2.5 built in functions of squilite. (
+    Closes: #518560 )
+  * Applied patch to finally install the contrib directory ( Closes:
+    #495019 )
+  * Raised compat version ( Closes: #497862 )
+
+ -- Luis Matos <gass@otiliamatos.ath.cx>  Mon, 30 Mar 2009 19:45:20 +0100
+
 trac (0.11.1-2.1) unstable; urgency=high
 
   * Non-maintainer upload.
diff -u trac-0.11.1/debian/README.Debian trac-0.11.1/debian/README.Debian
--- trac-0.11.1/debian/README.Debian
+++ trac-0.11.1/debian/README.Debian
@@ -13,6 +13,16 @@
   Trac uses SQLite (python-pysqlite2) as an embedded database, but 
 can be configured to use PostgreSQL or MySQL instead.
 
+Upgrading a Project Environment
+-------------------------------
+
+Bug: #501338 
+The project database from versions 0.10.x used sqlite v2.
+0.11.x versions use sqlite v3.
+To upgrade you must follow these steps:
+sqlite db/trac.db .dump | sqlite3 db/trac.db3
+
+
 Creating a Project Environment
 ------------------------------
   Trac Environment is the backend storage format where Trac stores 
diff -u trac-0.11.1/debian/control trac-0.11.1/debian/control
--- trac-0.11.1/debian/control
+++ trac-0.11.1/debian/control
@@ -1,8 +1,8 @@
 Source: trac
 Section: web
 Priority: optional
-Build-Depends-Indep: python-setuptools (> 0.5)
-Build-Depends: python-genshi (>= 0.5), python-central, python-all-dev, debhelper (>= 6.0.7), dpatch 
+Build-Depends-Indep: python-genshi (>= 0.5), python-central, python-all-dev, python-setuptools (> 0.5)
+Build-Depends: debhelper (>= 6.0.7), dpatch 
 Maintainer: Debian Trac Team <pkg-trac-devel@lists.alioth.debian.org>
 Uploaders: Otavio Salvador <otavio@debian.org>, Andres Salomon <dilinger@debian.org>, Jesus Climent <jesus.climent@hispalinux.es>, Luis Matos <gass@otiliamatos.ath.cx>
 Standards-Version: 3.8.0
@@ -13,7 +13,7 @@
 
 Package: trac
 Architecture: all
-Depends: ${python:Depends}, python-setuptools (> 0.5), python-pysqlite2 (>= 2.3.2), python-subversion, subversion (>= 1.0.1), python-genshi (>= 0.5), libjs-jquery
+Depends: ${python:Depends}, python-setuptools (> 0.5), python (>= 2.5) | python-pysqlite2 (>= 2.3.2), python-subversion, subversion (>= 1.0.1), python-genshi (>= 0.5), libjs-jquery
 Recommends: apache2 | httpd, python-pygments (>= 0.6) | enscript, python-tz
 Suggests: python-docutils, libapache2-mod-wsgi | libapache2-mod-python, python-psycopg2, python-mysqldb (>= 1.2.1), python-textile (>= 2.0), trac-git, trac-spamfilter, trac-bzr (>= 0.2+bzr45), trac-mercurial (>= 0.11.0.4)
 Conflicts: libapache2-mod-python2.3 (<< 3.2.8-3)
diff -u trac-0.11.1/debian/patches/00list trac-0.11.1/debian/patches/00list
--- trac-0.11.1/debian/patches/00list
+++ trac-0.11.1/debian/patches/00list
@@ -2,3 +2,2 @@
 15_remove_jquery_file.dpatch
-16_install_contrib_dir.dpatch
 17_SA32652.dpatch
reverted:
--- trac-0.11.1/debian/patches/16_install_contrib_dir.dpatch
+++ trac-0.11.1.orig/debian/patches/16_install_contrib_dir.dpatch
@@ -1,34 +0,0 @@
-#! /bin/sh /usr/share/dpatch/dpatch-run
-## 16_install_contrib_dir.dpatch by  <gass@otiliamatos.ath.cx>
-##
-## All lines beginning with `## DP:' are a description of the patch.
-## DP: Installs the contrib directory from trac source
-
-@DPATCH@
-
-diff --git a/setup.py b/setup.py
-index 37e61fb..c1334c6 100755
---- a/setup.py
-+++ b/setup.py
-@@ -13,6 +13,9 @@
- # history and logs, available at http://trac.edgewall.org/log/.
- 
- from setuptools import setup, find_packages
-+from glob import glob
-+
-+
- 
- setup(
-     name = 'Trac',
-@@ -48,7 +51,10 @@ facilities.
-         'trac.wiki': ['default-pages/*'],
-         'trac.ticket': ['workflows/*.ini'],
-     },
--
-+    data_files=[(('/usr/share/doc/trac/contrib/'), glob('contrib/*.*')),
-+                (('/usr/share/doc/trac/contrib/workflow/'), glob('contrib/workflow/*')),
-+                (('/usr/share/doc/trac/contrib/rpm/'), glob('contrib/rpm/*'))
-+    ],
-     test_suite = 'trac.test.suite',
-     zip_safe = False,
- 
only in patch2:
unchanged:
--- trac-0.11.1.orig/debian/install
+++ trac-0.11.1/debian/install
@@ -0,0 +1 @@
+contrib usr/share/doc/trac
only in patch2:
unchanged:
--- trac-0.11.1.orig/debian/patches/SA32652.dpatch
+++ trac-0.11.1/debian/patches/SA32652.dpatch
@@ -0,0 +1,2595 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## SA32652.dpatch by Giuseppe Iuculano <giuseppe@iuculano.it>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: No description.
+
+@DPATCH@
+diff -urNad trac-0.11.1~/trac/util/html.py trac-0.11.1/trac/util/html.py
+--- trac-0.11.1~/trac/util/html.py	2008-08-07 03:00:20.000000000 +0200
++++ trac-0.11.1/trac/util/html.py	2008-11-16 18:13:37.000000000 +0100
+@@ -14,10 +14,74 @@
+ import re
+ 
+ from genshi import Markup, escape, unescape
+-from genshi.core import stripentities, striptags
++from genshi.core import stripentities, striptags, START, END
+ from genshi.builder import Element, ElementFactory, Fragment
++from genshi.filters.html import HTMLSanitizer
+ 
+-__all__ = ['escape', 'unescape', 'html', 'plaintext']
++__all__ = ['escape', 'unescape', 'html', 'plaintext', 'TracHTMLSanitizer']
++
++
++class TracHTMLSanitizer(HTMLSanitizer):
++
++    UNSAFE_CSS = ['position']
++
++    def __init__(self):
++        safe_attrs = HTMLSanitizer.SAFE_ATTRS | set(['style'])
++        super(TracHTMLSanitizer, self).__init__(safe_attrs=safe_attrs)
++
++    def sanitize_css(self, text):
++        decls = []
++        text = self._strip_css_comments(self._replace_unicode_escapes(text))
++        for decl in filter(None, text.split(';')):
++            decl = decl.strip()
++            if not decl:
++                continue
++            try:
++                prop, value = decl.split(':', 1)
++            except ValueError:
++                continue
++            if not self.is_safe_css(prop.strip().lower(), value.strip()):
++                continue
++            is_evil = False
++            if 'expression' in decl:
++                is_evil = True
++            for match in re.finditer(r'url\s*\(([^)]+)', decl):
++                if not self.is_safe_uri(match.group(1)):
++                    is_evil = True
++                    break
++            if not is_evil:
++                decls.append(decl.strip())
++        return decls
++
++    def __call__(self, stream):
++        """Remove input type="password" elements from the stream
++        """
++        suppress = False
++        for kind, data, pos in super(TracHTMLSanitizer, self).__call__(stream):
++            if kind is START:
++                tag, attrs = data
++                if (tag == 'input' and
++                    attrs.get('type', '').lower() == 'password'):
++                    suppress = True
++                else:
++                    yield kind, data, pos
++            elif kind is END:
++                if not suppress:
++                    yield kind, data, pos
++                suppress = False
++            else:
++                yield kind, data, pos
++
++    def is_safe_css(self, prop, value):
++        """Determine whether the given css property declaration is to be 
++        considered safe for inclusion in the output.
++        """
++        if prop in self.UNSAFE_CSS:
++            return False
++        # Negative margins can be used for phishing
++        elif prop.startswith('margin') and '-' in value:
++            return False
++        return True
+ 
+ 
+ class Deuglifier(object):
+diff -urNad trac-0.11.1~/trac/wiki/formatter.py trac-0.11.1/trac/wiki/formatter.py
+--- trac-0.11.1~/trac/wiki/formatter.py	2008-08-07 03:00:20.000000000 +0200
++++ trac-0.11.1/trac/wiki/formatter.py	2008-11-16 18:15:09.000000000 +0100
+@@ -26,7 +26,6 @@
+ 
+ from genshi.builder import tag, Element
+ from genshi.core import Stream, Markup, escape
+-from genshi.filters import HTMLSanitizer
+ from genshi.input import HTMLParser, ParseError
+ from genshi.util import plaintext
+ 
+@@ -38,6 +37,7 @@
+ from trac.wiki.parser import WikiParser
+ from trac.util.text import shorten_line, to_unicode, \
+                            unicode_quote, unicode_quote_plus
++from trac.util.html import TracHTMLSanitizer
+ from trac.util.translation import _
+ 
+ __all__ = ['wiki_to_html', 'wiki_to_oneliner', 'wiki_to_outline',
+@@ -86,8 +86,7 @@
+                               'span': self._span_processor,
+                               'Span': self._span_processor}
+ 
+-        self._sanitizer = HTMLSanitizer(safe_attrs=HTMLSanitizer.SAFE_ATTRS |
+-                                        set(['style']))
++        self._sanitizer = TracHTMLSanitizer()
+         
+         self.processor = builtin_processors.get(name)
+         if not self.processor:
+diff -urNad trac-0.11.1~/trac/wiki/formatter.py.orig trac-0.11.1/trac/wiki/formatter.py.orig
+--- trac-0.11.1~/trac/wiki/formatter.py.orig	1970-01-01 01:00:00.000000000 +0100
++++ trac-0.11.1/trac/wiki/formatter.py.orig	2008-08-07 03:00:20.000000000 +0200
+@@ -0,0 +1,1139 @@
++# -*- coding: utf-8 -*-
++#
++# Copyright (C) 2003-2008 Edgewall Software
++# Copyright (C) 2003-2005 Jonas Borgström <jonas@edgewall.com>
++# Copyright (C) 2004-2005 Christopher Lenz <cmlenz@gmx.de>
++# Copyright (C) 2005-2007 Christian Boos <cboos@neuf.fr>
++# All rights reserved.
++#
++# This software is licensed as described in the file COPYING, which
++# you should have received as part of this distribution. The terms
++# are also available at http://trac.edgewall.org/wiki/TracLicense.
++#
++# This software consists of voluntary contributions made by many
++# individuals. For the exact contribution history, see the revision
++# history and logs, available at http://trac.edgewall.org/log/.
++#
++# Author: Jonas Borgström <jonas@edgewall.com>
++#         Christopher Lenz <cmlenz@gmx.de>
++#         Christian Boos <cboos@neuf.fr>
++
++import re
++import os
++import urllib
++
++from StringIO import StringIO
++
++from genshi.builder import tag, Element
++from genshi.core import Stream, Markup, escape
++from genshi.filters import HTMLSanitizer
++from genshi.input import HTMLParser, ParseError
++from genshi.util import plaintext
++
++from trac.core import *
++from trac.mimeview import *
++from trac.resource import get_relative_url
++from trac.util.compat import set
++from trac.wiki.api import WikiSystem, parse_args
++from trac.wiki.parser import WikiParser
++from trac.util.text import shorten_line, to_unicode, \
++                           unicode_quote, unicode_quote_plus
++from trac.util.translation import _
++
++__all__ = ['wiki_to_html', 'wiki_to_oneliner', 'wiki_to_outline',
++           'Formatter', 'format_to', 'format_to_html', 'format_to_oneliner',
++           'extract_link']
++
++def system_message(msg, text=None):
++    return tag.div(tag.strong(msg), text and tag.pre(text),
++                   class_="system-message")
++
++def _markup_to_unicode(markup):
++    stream = None
++    if isinstance(markup, Element):
++        stream = markup.generate()
++    elif isinstance(markup, Stream):
++        stream = markup
++    if stream:
++        markup = stream.render('xhtml', encoding=None, strip_whitespace=False)
++    return to_unicode(markup)
++
++
++class WikiProcessor(object):
++
++    _code_block_re = re.compile('^<div(?:\s+class="([^"]+)")?>(.*)</div>$')
++
++    def __init__(self, formatter, name, args={}):
++        """Find the processor by name
++        
++        :param formatter: the formatter embedding a call for this processor 
++        :param name: the name of the processor 
++        :param args: extra parameters for the processor
++
++        (since 0.11)
++        """
++        self.formatter = formatter
++        self.env = formatter.env
++        self.name = name
++        self.args = args
++        self.error = None
++        self.macro_provider = None
++
++        builtin_processors = {'html': self._html_processor,
++                              'default': self._default_processor,
++                              'comment': self._comment_processor,
++                              'div': self._div_processor,
++                              'span': self._span_processor,
++                              'Span': self._span_processor}
++
++        self._sanitizer = HTMLSanitizer(safe_attrs=HTMLSanitizer.SAFE_ATTRS |
++                                        set(['style']))
++        
++        self.processor = builtin_processors.get(name)
++        if not self.processor:
++            # Find a matching wiki macro
++            for macro_provider in WikiSystem(self.env).macro_providers:
++                for macro_name in macro_provider.get_macros():
++                    if self.name == macro_name:
++                        if hasattr(macro_provider, 'expand_macro'):
++                            self.processor = self._macro_processor
++                        else:
++                            self.processor = self._legacy_macro_processor
++                        self.macro_provider = macro_provider
++                        break
++        if not self.processor:
++            # Find a matching mimeview renderer
++            from trac.mimeview.api import Mimeview
++            mimetype = Mimeview(formatter.env).get_mimetype(self.name)
++            if mimetype:
++                self.name = mimetype
++                self.processor = self._mimeview_processor
++            else:
++                self.processor = self._default_processor
++                self.error = "No macro or processor named '%s' found" % name
++
++    # builtin processors
++
++    def _comment_processor(self, text):
++        return ''
++
++    def _default_processor(self, text):
++        return tag.pre(text, class_="wiki")
++
++    def _html_processor(self, text):
++        if WikiSystem(self.env).render_unsafe_content:
++            return Markup(text)
++        try:
++            stream = Stream(HTMLParser(StringIO(text)))
++            return (stream | self._sanitizer).render('xhtml', encoding=None)
++        except ParseError, e:
++            self.env.log.warn(e)
++            line = unicode(text).splitlines()[e.lineno - 1].strip()
++            return system_message(_('HTML parsing error: %(message)s',
++                                    message=escape(e.msg)), line)
++        
++    def _elt_processor(self, eltname, format_to, text, args):
++        elt = getattr(tag, eltname)(**args)
++        if not WikiSystem(self.env).render_unsafe_content:
++            sanitized_elt = getattr(tag, eltname)
++            for (k,data,pos) in (Stream(elt) | self._sanitizer):
++                sanitized_elt.attrib = data[1]
++                break # only look at START (elt,attrs)
++            elt = sanitized_elt
++        elt.append(format_to(self.env, self.formatter.context, text))
++        return elt
++
++    def _div_processor(self, text):
++        return self._elt_processor('div', format_to_html, text, self.args)
++    
++    def _span_processor(self, text):
++        args, kwargs = parse_args(text, strict=True)
++        return self._elt_processor('span', format_to_oneliner, ', '.join(args),
++                                   kwargs)
++
++    # generic processors
++
++    def _legacy_macro_processor(self, text): # TODO: remove in 0.12
++        self.env.log.warning('Executing pre-0.11 Wiki macro %s by provider %s'
++                             % (self.name, self.macro_provider))
++        return self.macro_provider.render_macro(self.formatter.req, self.name,
++                                                text)
++
++    def _macro_processor(self, text):
++        self.env.log.debug('Executing Wiki macro %s by provider %s'
++                           % (self.name, self.macro_provider))
++        return self.macro_provider.expand_macro(self.formatter, self.name,
++                                                text)
++
++    def _mimeview_processor(self, text):
++        return Mimeview(self.env).render(self.formatter.context,
++                                         self.name, text)
++    # TODO: use convert('text/html') instead of render
++
++    def process(self, text, in_paragraph=False):
++        if self.error:
++            text = system_message(tag('Error: Failed to load processor ',
++                                      tag.code(self.name)),
++                                  self.error)
++        else:
++            text = self.processor(text)
++        if not text:
++            return ''
++        if in_paragraph:
++            content_for_span = None
++            interrupt_paragraph = False
++            if isinstance(text, Element):
++                tagname = text.tag.lower()
++                if tagname == 'div':
++                    class_ = text.attrib.get('class', '')
++                    if class_ and 'code' in class_:
++                        content_for_span = text.children
++                    else:
++                        interrupt_paragraph = True
++                elif tagname == 'table':
++                    interrupt_paragraph = True
++            else:
++                text = to_unicode(text)
++                match = re.match(self._code_block_re, unicode(text))
++                if match:
++                    if match.group(1) and 'code' in match.group(1):
++                        content_for_span = match.group(2)
++                    else:
++                        interrupt_paragraph = True
++                elif text.startswith('<table'):
++                    interrupt_paragraph = True
++            if content_for_span:
++                text = tag.span(class_='code-block')(*content_for_span)
++            elif interrupt_paragraph:
++                text = "</p>%s<p>" % to_unicode(text)
++        return text
++
++
++class Formatter(object):
++    """Base Wiki formatter.
++
++    Parses and formats wiki text, in a given `Context`.
++    """
++    
++    flavor = 'default'
++
++    # 0.10 compatibility
++    INTERTRAC_SCHEME = WikiParser.INTERTRAC_SCHEME
++    QUOTED_STRING = WikiParser.QUOTED_STRING
++    LINK_SCHEME = WikiParser.LINK_SCHEME
++
++    def __init__(self, env, context):
++        """Note: `req` is still temporarily used."""
++        self.env = env
++        self.context = context
++        self.req = context.req
++        self.href = context.href
++        self.resource = context.resource
++        self.perm = context.perm
++        self.db = self.env.get_db_cnx() # FIXME: remove
++        self.wiki = WikiSystem(self.env)
++        self.wikiparser = WikiParser(self.env)
++        self._anchors = {}
++        self._open_tags = []
++
++    def split_link(self, target):
++        """Split a target along "?" and "#" in `(path, query, fragment)`."""
++        query = fragment = ''
++        idx = target.find('#')
++        if idx >= 0:
++            target, fragment = target[:idx], target[idx:]
++        idx = target.find('?')
++        if idx >= 0:
++            target, query = target[:idx], target[idx:]
++        return (target, query, fragment)
++
++    # -- Pre- IWikiSyntaxProvider rules (Font styles)
++    
++    def tag_open_p(self, tag):
++        """Do we currently have any open tag with `tag` as end-tag?"""
++        return tag in self._open_tags
++
++    def close_tag(self, tag):
++        tmp =  ''
++        for i in xrange(len(self._open_tags)-1, -1, -1):
++            tmp += self._open_tags[i][1]
++            if self._open_tags[i][1] == tag:
++                del self._open_tags[i]
++                for j in xrange(i, len(self._open_tags)):
++                    tmp += self._open_tags[j][0]
++                break
++        return tmp
++
++    def open_tag(self, open, close):
++        self._open_tags.append((open, close))
++
++    def simple_tag_handler(self, match, open_tag, close_tag):
++        """Generic handler for simple binary style tags"""
++        if self.tag_open_p((open_tag, close_tag)):
++            return self.close_tag(close_tag)
++        else:
++            self.open_tag(open_tag, close_tag)
++        return open_tag
++
++    def _bolditalic_formatter(self, match, fullmatch):
++        italic = ('<i>', '</i>')
++        italic_open = self.tag_open_p(italic)
++        tmp = ''
++        if italic_open:
++            tmp += italic[1]
++            self.close_tag(italic[1])
++        tmp += self._bold_formatter(match, fullmatch)
++        if not italic_open:
++            tmp += italic[0]
++            self.open_tag(*italic)
++        return tmp
++
++    def _bold_formatter(self, match, fullmatch):
++        return self.simple_tag_handler(match, '<strong>', '</strong>')
++
++    def _italic_formatter(self, match, fullmatch):
++        return self.simple_tag_handler(match, '<i>', '</i>')
++
++    def _underline_formatter(self, match, fullmatch):
++        return self.simple_tag_handler(match, '<span class="underline">',
++                                       '</span>')
++
++    def _strike_formatter(self, match, fullmatch):
++        return self.simple_tag_handler(match, '<del>', '</del>')
++
++    def _subscript_formatter(self, match, fullmatch):
++        return self.simple_tag_handler(match, '<sub>', '</sub>')
++
++    def _superscript_formatter(self, match, fullmatch):
++        return self.simple_tag_handler(match, '<sup>', '</sup>')
++
++    def _inlinecode_formatter(self, match, fullmatch):
++        return tag.tt(fullmatch.group('inline'))
++
++    def _inlinecode2_formatter(self, match, fullmatch):
++        return tag.tt(fullmatch.group('inline2'))
++
++    # -- Post- IWikiSyntaxProvider rules
++
++    # E-mails
++
++    def _email_formatter(self, match, fullmatch):
++        from trac.web.chrome import Chrome
++        omatch = Chrome(self.env).format_emails(self.context, match)
++        if omatch == match: # not obfuscated, make a link
++            return self._make_mail_link('mailto:'+match, match)
++        else:
++            return omatch
++
++    # HTML escape of &, < and >
++
++    def _htmlescape_formatter(self, match, fullmatch):
++        return match == "&" and "&amp;" or match == "<" and "&lt;" or "&gt;"
++
++    # Short form (shref) and long form (lhref) of TracLinks
++
++    def _unquote(self, text):
++        if text and text[0] in "'\"" and text[0] == text[-1]:
++            return text[1:-1]
++        else:
++            return text
++
++    def _shref_formatter(self, match, fullmatch):
++        ns = fullmatch.group('sns')
++        target = self._unquote(fullmatch.group('stgt'))
++        return self._make_link(ns, target, match, match, fullmatch)
++
++    def _lhref_formatter(self, match, fullmatch):
++        rel = fullmatch.group('rel')
++        ns = fullmatch.group('lns')
++        target = self._unquote(fullmatch.group('ltgt'))
++        label = fullmatch.group('label')
++        if not label: # e.g. `[http://target]` or `[wiki:target]`
++            if target:
++                if target.startswith('//'): # for `[http://target]`
++                    label = ns+':'+target   #  use `http://target`
++                else:                       # for `wiki:target`
++                    label = target          #  use only `target`
++            else: # e.g. `[search:]` 
++                label = ns
++        else:
++            label = self._unquote(label)
++        if rel:
++            path, query, fragment = self.split_link(rel)
++            if path.startswith('//'):
++                path = '/' + path.lstrip('/')
++            elif path.startswith('/'):
++                path = self.href(path)
++            else:
++                path = get_relative_url(self.env, self.resource, self.href,
++                                        path)
++                if '?' in path and query:
++                    query = '&' + query.lstrip('?')
++            return tag.a(label or rel, href=path + query + fragment)
++        else:
++            return self._make_link(ns, target, match, label, fullmatch)
++
++    def _make_link(self, ns, target, match, label, fullmatch):
++        # first check for an alias defined in trac.ini
++        ns = self.env.config['intertrac'].get(ns, ns)
++        if ns in self.wikiparser.link_resolvers:
++            return self.wikiparser.link_resolvers[ns](self, ns, target,
++                                                      escape(label, False))
++        elif target.startswith('//'):
++            return self._make_ext_link(ns+':'+target, label)
++        elif ns == "mailto":
++            from trac.web.chrome import Chrome
++            otarget = Chrome(self.env).format_emails(self.context, target)
++            olabel = Chrome(self.env).format_emails(self.context, label)
++            if (otarget, olabel) == (target, label):
++                return self._make_mail_link('mailto:'+target, label)
++            else:
++                return olabel or otarget
++        else:
++            if label == target and not fullmatch.group('label'):
++                # add ns for Inter* links when nothing is set
++                label = ns+':'+label
++            return self._make_intertrac_link(ns, target, label) or \
++                   self._make_interwiki_link(ns, target, label) or \
++                   escape(match)
++
++    def _make_intertrac_link(self, ns, target, label):
++        intertrac = self.env.config['intertrac']
++        url = intertrac.get(ns+'.url')
++        if not url and ns == 'trac':
++            url = 'http://trac.edgewall.org'
++        if url:
++            name = intertrac.get(ns+'.title', 'Trac project %s' % ns)
++            compat = intertrac.getbool(ns+'.compat', 'false')
++            # set `compat` default to False now that 0.10 is widely used
++            # TODO: remove compatibility code completely for 1.0 release
++            if compat:
++                sep = target.find(':')
++                if sep != -1:
++                    url = '%s/%s/%s' % (url, target[:sep], target[sep + 1:])
++                else: 
++                    url = '%s/search?q=%s' % (url, unicode_quote_plus(target))
++            else:
++                url = '%s/intertrac/%s' % (url, unicode_quote(target))
++            if target:
++                title = '%s in %s' % (target, name)
++            else:
++                title = name
++            return self._make_ext_link(url, label, title)
++        else:
++            return None
++
++    def shorthand_intertrac_helper(self, ns, target, label, fullmatch):
++        if fullmatch: # short form
++            it_group = fullmatch.group('it_%s' % ns)
++            if it_group:
++                alias = it_group.strip()
++                intertrac = self.env.config['intertrac']
++                target = '%s:%s' % (ns, target[len(it_group):])
++                return self._make_intertrac_link(intertrac.get(alias, alias),
++                                                 target, label) or label
++        return None
++
++    def _make_interwiki_link(self, ns, target, label):
++        from trac.wiki.interwiki import InterWikiMap        
++        interwiki = InterWikiMap(self.env)
++        if ns in interwiki:
++            url, title = interwiki.url(ns, target)
++            return self._make_ext_link(url, label, title)
++        else:
++            return None
++
++    def _make_ext_link(self, url, text, title=''):
++        local_url = self.env.config.get('project', 'url') or \
++                    (self.req or self.env).abs_href.base
++        if not url.startswith(local_url):
++            return tag.a(tag.span(text, class_="icon"),
++                          class_="ext-link", href=url, title=title or None)
++        else:
++            return tag.a(text, href=url, title=title or None)
++
++    def _make_mail_link(self, url, text, title=''):
++        return tag.a(tag.span(text, class_="icon"),
++                      class_="mail-link", href=url, title=title or None)
++
++    # WikiMacros
++    
++    def _macro_formatter(self, match, fullmatch):
++        name = fullmatch.group('macroname')
++        if name.lower() == 'br':
++            return '<br />'
++        args = fullmatch.group('macroargs')
++        try:
++            macro = WikiProcessor(self, name)
++            return macro.process(args, in_paragraph=True)
++        except Exception, e:
++            self.env.log.error('Macro %s(%s) failed' % (name, args),
++                               exc_info=True)
++            return system_message('Error: Macro %s(%s) failed' % (name, args),
++                                  e)
++
++    # Headings
++
++    def _parse_heading(self, match, fullmatch, shorten):
++        match = match.strip()
++
++        depth = min(len(fullmatch.group('hdepth')), 5)
++        anchor = fullmatch.group('hanchor') or ''
++        heading_text = match[depth+1:-depth-1-len(anchor)]
++        heading = format_to_oneliner(self.env, self.context, heading_text,
++                                     False)
++        if anchor:
++            anchor = anchor[1:]
++        else:
++            sans_markup = plaintext(heading, keeplinebreaks=False)
++            anchor = WikiParser._anchor_re.sub('', sans_markup)
++            if not anchor or anchor[0].isdigit() or anchor[0] in '.-':
++                # an ID must start with a Name-start character in XHTML
++                anchor = 'a' + anchor # keeping 'a' for backward compat
++        i = 1
++        anchor_base = anchor
++        while anchor in self._anchors:
++            anchor = anchor_base + str(i)
++            i += 1
++        self._anchors[anchor] = True
++        if shorten:
++            heading = format_to_oneliner(self.env, self.context, heading_text,
++                                         True)
++        return (depth, heading, anchor)
++
++    def _heading_formatter(self, match, fullmatch):
++        self.close_table()
++        self.close_paragraph()
++        self.close_indentation()
++        self.close_list()
++        self.close_def_list()
++        depth, heading, anchor = self._parse_heading(match, fullmatch, False)
++        self.out.write('<h%d id="%s">%s</h%d>' %
++                       (depth, anchor, heading, depth))
++
++    # Generic indentation (as defined by lists and quotes)
++
++    def _set_tab(self, depth):
++        """Append a new tab if needed and truncate tabs deeper than `depth`
++
++        given:       -*-----*--*---*--
++        setting:              *
++        results in:  -*-----*-*-------
++        """
++        tabstops = []
++        for ts in self._tabstops:
++            if ts >= depth:
++                break
++            tabstops.append(ts)
++        tabstops.append(depth)
++        self._tabstops = tabstops
++
++    # Lists
++    
++    def _list_formatter(self, match, fullmatch):
++        ldepth = len(fullmatch.group('ldepth'))
++        listid = match[ldepth]
++        self.in_list_item = True
++        class_ = start = None
++        if listid in '-*':
++            type_ = 'ul'
++        else:
++            type_ = 'ol'
++            idx = '01iI'.find(listid)
++            if idx >= 0:
++                class_ = ('arabiczero', None, 'lowerroman', 'upperroman')[idx]
++            elif listid.isdigit():
++                start = match[ldepth:match.find('.')]
++            elif listid.islower():
++                class_ = 'loweralpha'
++            elif listid.isupper():
++                class_ = 'upperalpha'
++        self._set_list_depth(ldepth, type_, class_, start)
++        return ''
++        
++    def _get_list_depth(self):
++        """Return the space offset associated to the deepest opened list."""
++        return self._list_stack and self._list_stack[-1][1] or 0
++
++    def _set_list_depth(self, depth, new_type, list_class, start):
++        def open_list():
++            self.close_table()
++            self.close_paragraph()
++            self.close_indentation() # FIXME: why not lists in quotes?
++            self._list_stack.append((new_type, depth))
++            self._set_tab(depth)
++            class_attr = (list_class and ' class="%s"' % list_class) or ''
++            start_attr = (start and ' start="%s"' % start) or ''
++            self.out.write('<'+new_type+class_attr+start_attr+'><li>')
++        def close_list(tp):
++            self._list_stack.pop()
++            self.out.write('</li></%s>' % tp)
++
++        # depending on the indent/dedent, open or close lists
++        if depth > self._get_list_depth():
++            open_list()
++        else:
++            while self._list_stack:
++                deepest_type, deepest_offset = self._list_stack[-1]
++                if depth >= deepest_offset:
++                    break
++                close_list(deepest_type)
++            if depth > 0:
++                if self._list_stack:
++                    old_type, old_offset = self._list_stack[-1]
++                    if new_type and old_type != new_type:
++                        close_list(old_type)
++                        open_list()
++                    else:
++                        if old_offset != depth: # adjust last depth
++                            self._list_stack[-1] = (old_type, depth)
++                        self.out.write('</li><li>')
++                else:
++                    open_list()
++
++    def close_list(self):
++        self._set_list_depth(0, None, None, None)
++
++    # Definition Lists
++
++    def _definition_formatter(self, match, fullmatch):
++        tmp = self.in_def_list and '</dd>' or '<dl>'
++        definition = match[:match.find('::')]
++        tmp += '<dt>%s</dt><dd>' % format_to_oneliner(self.env, self.context,
++                                                      definition)
++        self.in_def_list = True
++        return tmp
++
++    def close_def_list(self):
++        if self.in_def_list:
++            self.out.write('</dd></dl>\n')
++        self.in_def_list = False
++
++    # Blockquote
++
++    def _indent_formatter(self, match, fullmatch):
++        idepth = len(fullmatch.group('idepth'))
++        if self._list_stack:
++            ltype, ldepth = self._list_stack[-1]
++            if idepth < ldepth:
++                for _, ldepth in self._list_stack:
++                    if idepth > ldepth:
++                        self.in_list_item = True
++                        self._set_list_depth(idepth, None, None, None)
++                        return ''
++            elif idepth <= ldepth + (ltype == 'ol' and 3 or 2):
++                self.in_list_item = True
++                return ''
++        if not self.in_def_list:
++            self._set_quote_depth(idepth)
++        return ''
++
++    def _citation_formatter(self, match, fullmatch):
++        cdepth = len(fullmatch.group('cdepth').replace(' ', ''))
++        self._set_quote_depth(cdepth, True)
++        return ''
++
++    def close_indentation(self):
++        self._set_quote_depth(0)
++
++    def _get_quote_depth(self):
++        """Return the space offset associated to the deepest opened quote."""
++        return self._quote_stack and self._quote_stack[-1] or 0
++
++    def _set_quote_depth(self, depth, citation=False):
++        def open_quote(depth):
++            self.close_table()
++            self.close_paragraph()
++            self.close_list()
++            def open_one_quote(d):
++                self._quote_stack.append(d)
++                self._set_tab(d)
++                class_attr = citation and ' class="citation"' or ''
++                self.out.write('<blockquote%s>' % class_attr + os.linesep)
++            if citation:
++                for d in range(quote_depth+1, depth+1):
++                    open_one_quote(d)
++            else:
++                open_one_quote(depth)
++        def close_quote():
++            self.close_table()
++            self.close_paragraph()
++            self._quote_stack.pop()
++            self.out.write('</blockquote>' + os.linesep)
++        quote_depth = self._get_quote_depth()
++        if depth > quote_depth:
++            self._set_tab(depth)
++            tabstops = self._tabstops[::-1]
++            while tabstops:
++                tab = tabstops.pop()
++                if tab > quote_depth:
++                    open_quote(tab)
++        else:
++            while self._quote_stack:
++                deepest_offset = self._quote_stack[-1]
++                if depth >= deepest_offset:
++                    break
++                close_quote()
++            if not citation and depth > 0:
++                if self._quote_stack:
++                    old_offset = self._quote_stack[-1]
++                    if old_offset != depth: # adjust last depth
++                        self._quote_stack[-1] = depth
++                else:
++                    open_quote(depth)
++        if depth > 0:
++            self.in_quote = True
++
++    # Table
++    
++    def _last_table_cell_formatter(self, match, fullmatch):
++        return ''
++
++    def _table_cell_formatter(self, match, fullmatch):
++        self.open_table()
++        self.open_table_row()
++        if self.in_table_cell:
++            return '</td><td>'
++        else:
++            self.in_table_cell = 1
++            return '<td>'
++
++    def open_table(self):
++        if not self.in_table:
++            self.close_paragraph()
++            self.close_list()
++            self.close_def_list()
++            self.in_table = 1
++            self.out.write('<table class="wiki">' + os.linesep)
++
++    def open_table_row(self):
++        if not self.in_table_row:
++            self.open_table()
++            self.in_table_row = 1
++            self.out.write('<tr>')
++
++    def close_table_row(self):
++        if self.in_table_row:
++            self.in_table_row = 0
++            if self.in_table_cell:
++                self.in_table_cell = 0
++                self.out.write('</td>')
++
++            self.out.write('</tr>')
++
++    def close_table(self):
++        if self.in_table:
++            self.close_table_row()
++            self.out.write('</table>' + os.linesep)
++            self.in_table = 0
++
++    # Paragraphs
++
++    def open_paragraph(self):
++        if not self.paragraph_open:
++            self.out.write('<p>' + os.linesep)
++            self.paragraph_open = 1
++
++    def close_paragraph(self):
++        if self.paragraph_open:
++            while self._open_tags != []:
++                self.out.write(self._open_tags.pop()[1])
++            self.out.write('</p>' + os.linesep)
++            self.paragraph_open = 0
++
++    # Code blocks
++    
++    def handle_code_block(self, line):
++        if line.strip() == WikiParser.STARTBLOCK:
++            self.in_code_block += 1
++            if self.in_code_block == 1:
++                self.code_processor = None
++                self.code_buf = []
++            else:
++                self.code_buf.append(line)
++                if not self.code_processor:
++                    self.code_processor = WikiProcessor(self, 'default')
++        elif line.strip() == WikiParser.ENDBLOCK:
++            self.in_code_block -= 1
++            if self.in_code_block == 0 and self.code_processor:
++                self.close_table()
++                self.close_paragraph()
++                if self.code_buf:
++                    self.code_buf.append('')
++                code_text = os.linesep.join(self.code_buf)
++                processed = self.code_processor.process(code_text)
++                self.out.write(_markup_to_unicode(processed))
++
++            else:
++                self.code_buf.append(line)
++        elif not self.code_processor:
++            match = WikiParser._processor_re.match(line)
++            if match:
++                name = match.group(1)
++                args = WikiParser._processor_param_re.split(line[len(name):])
++                del args[::3]
++                keys = [str(k) for k in args[::2]] # used as keyword parameters
++                values = [v and v[0] in '"\'' and v[1:-1] or v
++                          for v in args[1::2]]
++                args = dict(zip(keys, values))
++                self.code_processor = WikiProcessor(self, name, args)
++            else:
++                self.code_buf.append(line)
++                self.code_processor = WikiProcessor(self, 'default')
++        else:
++            self.code_buf.append(line)
++
++    def close_code_blocks(self):
++        while self.in_code_block > 0:
++            self.handle_code_block(WikiParser.ENDBLOCK)
++
++    # -- Wiki engine
++    
++    def handle_match(self, fullmatch):
++        for itype, match in fullmatch.groupdict().items():
++            if match and not itype in self.wikiparser.helper_patterns:
++                # Check for preceding escape character '!'
++                if match[0] == '!':
++                    return escape(match[1:])
++                if itype in self.wikiparser.external_handlers:
++                    external_handler = self.wikiparser.external_handlers[itype]
++                    return external_handler(self, match, fullmatch)
++                else:
++                    internal_handler = getattr(self, '_%s_formatter' % itype)
++                    return internal_handler(match, fullmatch)
++
++    def replace(self, fullmatch):
++        """Replace one match with its corresponding expansion"""
++        replacement = self.handle_match(fullmatch)
++        if replacement:
++            return _markup_to_unicode(replacement)
++
++    def reset(self, source, out=None):
++        self.source = source
++        class NullOut(object):
++            def write(self, data): pass
++        self.out = out or NullOut()
++        self._open_tags = []
++        self._list_stack = []
++        self._quote_stack = []
++        self._tabstops = []
++
++        self.in_code_block = 0
++        self.in_table = 0
++        self.in_def_list = 0
++        self.in_table_row = 0
++        self.in_table_cell = 0
++        self.paragraph_open = 0
++
++    def format(self, text, out=None, escape_newlines=False):
++        self.reset(text, out)
++        for line in text.splitlines():
++            # Handle code block
++            if self.in_code_block or line.strip() == WikiParser.STARTBLOCK:
++                self.handle_code_block(line)
++                continue
++            # Handle Horizontal ruler
++            elif line[0:4] == '----':
++                self.close_table()
++                self.close_paragraph()
++                self.close_indentation()
++                self.close_list()
++                self.close_def_list()
++                self.out.write('<hr />' + os.linesep)
++                continue
++            # Handle new paragraph
++            elif line == '':
++                self.close_paragraph()
++                self.close_indentation()
++                self.close_list()
++                self.close_def_list()
++                continue
++
++            # Tab expansion and clear tabstops if no indent
++            line = line.replace('\t', ' '*8)
++            if not line.startswith(' '):
++                self._tabstops = []
++
++            self.in_list_item = False
++            self.in_quote = False
++            # Throw a bunch of regexps on the problem
++            result = re.sub(self.wikiparser.rules, self.replace, line)
++
++            if not self.in_list_item:
++                self.close_list()
++
++            if not self.in_quote:
++                self.close_indentation()
++
++            if self.in_def_list and not line.startswith(' '):
++                self.close_def_list()
++
++            if self.in_table and not line.lstrip().startswith('||'):
++                self.close_table()
++
++            sep = os.linesep
++            if not(self.in_list_item or self.in_def_list or self.in_table):
++                if len(result):
++                    self.open_paragraph()
++                if escape_newlines and not result.rstrip().endswith('<br />'):
++                    sep = '<br />' + sep
++            self.out.write(result + sep)
++            self.close_table_row()
++
++        self.close_table()
++        self.close_paragraph()
++        self.close_indentation()
++        self.close_list()
++        self.close_def_list()
++        self.close_code_blocks()
++
++
++class OneLinerFormatter(Formatter):
++    """
++    A special version of the wiki formatter that only implement a
++    subset of the wiki formatting functions. This version is useful
++    for rendering short wiki-formatted messages on a single line
++    """
++    flavor = 'oneliner'
++
++    def __init__(self, env, context):
++        Formatter.__init__(self, env, context)
++
++    # Override a few formatters to disable some wiki syntax in "oneliner"-mode
++    def _list_formatter(self, match, fullmatch): return match
++    def _indent_formatter(self, match, fullmatch): return match
++    def _citation_formatter(self, match, fullmatch):
++        return escape(match, False)
++    def _heading_formatter(self, match, fullmatch):
++        return escape(match, False)
++    def _definition_formatter(self, match, fullmatch):
++        return escape(match, False)
++    def _table_cell_formatter(self, match, fullmatch): return match
++    def _last_table_cell_formatter(self, match, fullmatch): return match
++
++    def _macro_formatter(self, match, fullmatch):
++        name = fullmatch.group('macroname')
++        if name.lower() == 'br':
++            return ' '
++        elif name == 'comment':
++            return ''
++        else:
++            args = fullmatch.group('macroargs')
++            return '[[%s%s]]' % (name,  args and '(...)' or '')
++
++    def format(self, text, out, shorten=False):
++        if not text:
++            return
++        self.reset(text, out)
++
++        # Simplify code blocks
++        in_code_block = 0
++        processor = None
++        buf = StringIO()
++        for line in text.strip().splitlines():
++            if line.strip() == WikiParser.STARTBLOCK:
++                in_code_block += 1
++            elif line.strip() == WikiParser.ENDBLOCK:
++                if in_code_block:
++                    in_code_block -= 1
++                    if in_code_block == 0:
++                        if processor != 'comment':
++                            buf.write(' [...]' + os.linesep)
++                        processor = None
++            elif in_code_block:
++                if not processor:
++                    if line.startswith('#!'):
++                        processor = line[2:].strip()
++            else:
++                buf.write(line + os.linesep)
++        result = buf.getvalue()[:-len(os.linesep)]
++
++        if shorten:
++            result = shorten_line(result)
++
++        result = re.sub(self.wikiparser.rules, self.replace, result)
++        result = result.replace('[...]', u'[\u2026]')
++        if result.endswith('...'):
++            result = result[:-3] + u'\u2026'
++
++        # Close all open 'one line'-tags
++        result += self.close_tag(None)
++        # Flush unterminated code blocks
++        if in_code_block > 0:
++            result += u'[\u2026]'
++        out.write(result)
++
++
++class OutlineFormatter(Formatter):
++    """Special formatter that generates an outline of all the headings."""
++    flavor = 'outline'
++    
++    def __init__(self, env, context):
++        Formatter.__init__(self, env, context)
++
++    # Avoid the possible side-effects of rendering WikiProcessors
++
++    def _macro_formatter(self, match, fullmatch):
++        return ''
++
++    def handle_code_block(self, line):
++        if line.strip() == WikiParser.STARTBLOCK:
++            self.in_code_block += 1
++        elif line.strip() == WikiParser.ENDBLOCK:
++            self.in_code_block -= 1
++
++    def format(self, text, out, max_depth=6, min_depth=1):
++        self.outline = []
++        Formatter.format(self, text)
++
++        if min_depth > max_depth:
++            min_depth, max_depth = max_depth, min_depth
++        max_depth = min(6, max_depth)
++        min_depth = max(1, min_depth)
++
++        curr_depth = min_depth - 1
++        for depth, anchor, text in self.outline:
++            if depth < min_depth or depth > max_depth:
++                continue
++            if depth < curr_depth:
++                out.write('</li></ol>' * (curr_depth - depth))
++                out.write("</li><li>\n")
++            elif depth > curr_depth:
++                out.write('<ol><li>' * (depth - curr_depth))
++            else:
++                out.write("</li><li>\n")
++            curr_depth = depth
++            out.write('<a href="#%s">%s</a>' % (anchor, text))
++        out.write('</li></ol>' * curr_depth)
++
++    def _heading_formatter(self, match, fullmatch):
++        depth, heading, anchor = self._parse_heading(match, fullmatch, True)
++        heading = re.sub(r'</?a(?: .*?)?>', '', heading) # Strip out link tags
++        self.outline.append((depth, anchor, heading))
++
++
++class LinkFormatter(OutlineFormatter):
++    """Special formatter that focuses on TracLinks."""
++    flavor = 'link'
++    
++    def __init__(self, env, context):
++        OutlineFormatter.__init__(self, env, context)
++
++    def _heading_formatter(self, match, fullmatch):
++         return ''
++
++    def match(self, wikitext):
++        """Return the Wiki match found at the beginning of the `wikitext`"""
++        self.reset(wikitext)        
++        match = re.match(self.wikiparser.rules, wikitext)
++        if match:
++            return self.handle_match(match)
++
++
++# Pure Wiki Formatter
++
++class HtmlFormatter(object):
++    """Format parsed wiki text to HTML"""
++
++    flavor = 'default'
++    
++    def __init__(self, env, context, wikidom):
++        self.env = env
++        self.context = context
++        if isinstance(wikidom, basestring):
++            wikidom = WikiParser(env).parse(wikidom)
++        self.wikidom = wikidom
++
++    def generate(self, escape_newlines=False):
++        """Generate HTML elements.
++
++        newlines in the wikidom will be preserved if `escape_newlines` is set.
++        """
++        # FIXME: compatibility code only for now
++        out = StringIO()
++        Formatter(self.env, self.context).format(self.wikidom, out,
++                                                 escape_newlines)
++        return Markup(out.getvalue())
++
++
++class InlineHtmlFormatter(object):
++    """Format parsed wiki text to inline elements HTML.
++
++    Block level content will be disguarded or compacted.
++    """
++    
++    flavor = 'oneliner'
++
++    def __init__(self, env, context, wikidom):
++        self.env = env
++        self.context = context
++        if isinstance(wikidom, basestring):
++            wikidom = WikiParser(env).parse(wikidom)
++        self.wikidom = wikidom
++
++    def generate(self, shorten=False):
++        """Generate HTML inline elements.
++
++        If `shorten` is set, the generation will stop once enough characters
++        have been emitted.
++        """
++        # FIXME: compatibility code only for now
++        out = StringIO()
++        OneLinerFormatter(self.env, self.context).format(self.wikidom, out,
++                                                         shorten)
++        return Markup(out.getvalue())
++
++
++def format_to(env, flavor, context, wikidom, **options):
++    if flavor == 'oneliner':
++        return format_to_oneliner(env, context, wikidom, **options)
++    else:
++        return format_to_html(env, context, wikidom, **options)
++
++def format_to_html(env, context, wikidom, escape_newlines=False):
++    if not wikidom:
++        return Markup()
++    return HtmlFormatter(env, context, wikidom).generate(escape_newlines)
++
++def format_to_oneliner(env, context, wikidom, shorten=False):
++    if not wikidom:
++        return Markup()
++    return InlineHtmlFormatter(env, context, wikidom).generate(shorten)
++
++def extract_link(env, context, wikidom):
++    if not wikidom:
++        return Markup()
++    return LinkFormatter(env, context).match(wikidom)
++
++
++# pre-0.11 wiki text to Markup compatibility methods
++
++def wiki_to_html(wikitext, env, req, db=None,
++                 absurls=False, escape_newlines=False):
++    if not wikitext:
++        return Markup()
++    abs_ref, href = (req or env).abs_href, (req or env).href
++    context = Context.from_request(req, absurls=absurls)
++    out = StringIO()
++    Formatter(env, context).format(wikitext, out, escape_newlines)
++    return Markup(out.getvalue())
++
++def wiki_to_oneliner(wikitext, env, db=None, shorten=False, absurls=False,
++                     req=None):
++    if not wikitext:
++        return Markup()
++    abs_ref, href = (req or env).abs_href, (req or env).href
++    context = Context.from_request(req, absurls=absurls)
++    out = StringIO()
++    OneLinerFormatter(env, context).format(wikitext, out, shorten)
++    return Markup(out.getvalue())
++
++def wiki_to_outline(wikitext, env, db=None,
++                    absurls=False, max_depth=None, min_depth=None):
++    if not wikitext:
++        return Markup()
++    abs_ref, href = (req or env).abs_href, (req or env).href
++    context = Context.from_request(req, absurls=absurls)
++    out = StringIO()
++    OutlineFormatter(env, context).format(wikitext, out, max_depth, min_depth)
++    return Markup(out.getvalue())
+diff -urNad trac-0.11.1~/trac/wiki/parser.py trac-0.11.1/trac/wiki/parser.py
+--- trac-0.11.1~/trac/wiki/parser.py	2008-08-07 03:00:20.000000000 +0200
++++ trac-0.11.1/trac/wiki/parser.py	2008-11-16 18:16:22.000000000 +0100
+@@ -98,9 +98,10 @@
+         #  * list
+         r"(?P<list>^(?P<ldepth>\s+)(?:[-*]|\d+\.|[a-zA-Z]\.|[ivxIVX]{1,5}\.) )",
+         # definition:: 
+-        r"(?P<definition>^\s+((?:%s[^%s]*%s|%s.*?%s|[^%s%s:]|:[^:])+::)(?:\s+|$))"
++        r"(?P<definition>^\s+((?:%s[^%s]*%s|%s(?:%s{,2}[^%s])*?%s|[^%s%s:]|:[^:])+::)(?:\s+|$))"
+         % (INLINE_TOKEN, INLINE_TOKEN, INLINE_TOKEN,
+-           STARTBLOCK_TOKEN, ENDBLOCK_TOKEN, INLINE_TOKEN, STARTBLOCK[0]),
++           STARTBLOCK_TOKEN, ENDBLOCK[0], ENDBLOCK[0], ENDBLOCK_TOKEN,
++           INLINE_TOKEN, STARTBLOCK[0]),
+         # (leading space)
+         r"(?P<indent>^(?P<idepth>\s+)(?=\S))",
+         # || table ||
+diff -urNad trac-0.11.1~/trac/wiki/tests/wiki-tests.txt trac-0.11.1/trac/wiki/tests/wiki-tests.txt
+--- trac-0.11.1~/trac/wiki/tests/wiki-tests.txt	2008-08-07 03:00:20.000000000 +0200
++++ trac-0.11.1/trac/wiki/tests/wiki-tests.txt	2008-11-16 18:16:53.000000000 +0100
+@@ -1034,6 +1034,16 @@
+ </blockquote>
+ ------------------------------
+ term::definition
++============================== Pathological definition list counter example with block quotes
++ {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}} {{{a}}}
++------------------------------
++<blockquote>
++<p>
++<tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt>
++</p>
++</blockquote>
++------------------------------
++<tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt> <tt>a</tt>
+ ============================== Definition list + escaped definition list
+  complex topic:: multiline
+                  `not:: a dl`
+diff -urNad trac-0.11.1~/trac/wiki/tests/wiki-tests.txt.orig trac-0.11.1/trac/wiki/tests/wiki-tests.txt.orig
+--- trac-0.11.1~/trac/wiki/tests/wiki-tests.txt.orig	1970-01-01 01:00:00.000000000 +0100
++++ trac-0.11.1/trac/wiki/tests/wiki-tests.txt.orig	2008-08-07 03:00:20.000000000 +0200
+@@ -0,0 +1,1296 @@
++============================================================
++
++        Font styles
++
++============================== Bold + italic markup
++This should be '''''bold and italic'''''
++------------------------------
++<p>
++This should be <strong><i>bold and italic</i></strong>
++</p>
++------------------------------
++============================== Consecutive bold + italic markup
++'''''one''''', '''''two''''', '''''three''''', '''''four'''''
++------------------------------
++<p>
++<strong><i>one</i></strong>, <strong><i>two</i></strong>, <strong><i>three</i></strong>, <strong><i>four</i></strong>
++</p>
++------------------------------
++============================== Underline + overstrike markup
++__~~underlineoversrike~~__
++------------------------------
++<p>
++<span class="underline"><del>underlineoversrike</del></span>
++</p>
++------------------------------
++============================== Problematic markup: overlapping tags
++__~~overlapping__tags~~
++------------------------------
++<p>
++<span class="underline"><del>overlapping</del></span><del>tags</del>
++</p>
++------------------------------
++============================== Problematic markup: out of order close tags
++__~~outoforderclosetags__~~
++------------------------------
++<p>
++<span class="underline"><del>outoforderclosetags</del></span><del></del>
++</p>
++------------------------------
++============================== Problematic markup: bold + missing close italic
++'''''bolditalic''' # Open italic should be closed before paragraph end
++------------------------------
++<p>
++<strong><i>bolditalic</i></strong><i> # Open italic should be closed before paragraph end
++</i></p>
++------------------------------
++============================== Italic immediately followed by bold markup
++''italic'''''bold'''
++------------------------------
++<p>
++<i>italic</i><strong>bold</strong>
++</p>
++------------------------------
++============================== Bold immediately followed by italic markup
++'''bold'''''italic''
++------------------------------
++<p>
++<strong>bold</strong><i>italic</i>
++</p>
++------------------------------
++============================== Multiline bold italic markup
++'''''bold
++italic
++multiline'''''
++------------------------------
++<p>
++<strong><i>bold
++italic
++multiline</i></strong>
++</p>
++------------------------------
++============================== Problematic multiline bold italic markup
++'''''bold
++italic
++multiline
++without endtags
++------------------------------
++<p>
++<strong><i>bold
++italic
++multiline
++without endtags
++</i></strong></p>
++------------------------------
++============================== Super and subscript markup
++^superscript^, ,,subscript,,, normal.
++------------------------------
++<p>
++<sup>superscript</sup>, <sub>subscript</sub>, normal.
++</p>
++------------------------------
++<sup>superscript</sup>, <sub>subscript</sub>, normal.
++============================== Escaping markup
++!'''''foobar!''''' x
++!''foo!'' x
++!'''bar!''' x
++!__foo!__ x
++!~~bar!~~ x
++!,,boo!,, x
++!^baz!^ x
++------------------------------
++<p>
++'''''foobar''''' x
++''foo'' x
++'''bar''' x
++__foo__ x
++~~bar~~ x
++,,boo,, x
++^baz^ x
++</p>
++------------------------------
++============================== Complex mixed verbatim markup
++{{{verbatim}}}
++{{{
++{{{in `block`
++}}}
++`{{{this is verbatim}}}` and {{{`that` should also `be` verbatim}}}
++------------------------------
++<p>
++<tt>verbatim</tt>
++</p>
++<pre class="wiki">{{{in `block`
++</pre><p>
++<tt>{{{this is verbatim}}}</tt> and <tt>`that` should also `be` verbatim</tt>
++</p>
++------------------------------
++<tt>verbatim</tt>
++ […]
++<tt>{{{this is verbatim}}}</tt> and <tt>`that` should also `be` verbatim</tt>
++============================================================
++
++        Link Resolvers
++
++============================== Link resolvers, short form
++link:1
++
++Thing [link:1] Thing[link:2]
++------------------------------
++<p>
++<a class="odd resolver" href="/thing/1">link:1</a>
++</p>
++<p>
++Thing <a class="odd resolver" href="/thing/1">1</a> Thing<a class="even resolver" href="/thing/2">2</a>
++</p>
++------------------------------
++============================== Escaping links resolvers, short form
++!link:1
++Thing ![link:1 number 1], CS![link:1], ![link:bar]
++------------------------------
++<p>
++link:1
++Thing [link:1 number 1], CS[link:1], [link:bar]
++</p>
++------------------------------
++============================== Link resolvers, long form with label
++[link:1 thing one], [http://www.edgewall.com/ edgewall]
++------------------------------
++<p>
++<a class="odd resolver" href="/thing/1">thing one</a>, <a class="ext-link" href="http://www.edgewall.com/";><span class="icon">edgewall</span></a>
++</p>
++------------------------------
++============================== Link resolver SHREF_TARGET_LAST
++Add-on to link:123:
++Some change.
++link:1
++This ticket is the first one
++link:123>
++link:123&
++see link:xü.
++------------------------------
++<p>
++Add-on to <a class="odd resolver" href="/thing/123">link:123</a>:
++Some change.
++<a class="odd resolver" href="/thing/1">link:1</a>
++This ticket is the first one
++<a class="odd resolver" href="/thing/123">link:123</a>&gt;
++<a class="odd resolver" href="/thing/123">link:123</a>&amp;
++see <a class="text resolver" href="/stuff/x%C3%BC">link:xü</a>.
++</p>
++------------------------------
++Add-on to <a class="odd resolver" href="/thing/123">link:123</a>:
++Some change.
++<a class="odd resolver" href="/thing/1">link:1</a>
++This ticket is the first one
++<a class="odd resolver" href="/thing/123">link:123</a>&gt;
++<a class="odd resolver" href="/thing/123">link:123</a>&amp;
++see <a class="text resolver" href="/stuff/x%C3%BC">link:xü</a>.
++============================== Link resolver SHREF_TARGET_FIRST
++<bug>http://localhost/bugzilla/show_bug.cgi?id=1284</bug> 804
++__Summary:__
++see link:Überflüssigkeit
++------------------------------
++<p>
++&lt;bug&gt;<a class="ext-link" href="http://localhost/bugzilla/show_bug.cgi?id=1284";><span class="icon">http://localhost/bugzilla/show_bug.cgi?id=1284</span></a>&lt;/bug&gt; 804
++<span class="underline">Summary:</span>
++see <a class="text resolver" href="/stuff/%C3%9Cberfl%C3%BCssigkeit">link:Überflüssigkeit</a>
++</p>
++------------------------------
++============================== Link resolver SHREF_TARGET_MIDDLE
++||http://example.com/img.png||text||
++------------------------------
++<table class="wiki">
++<tr><td><a class="ext-link" href="http://example.com/img.png";><span class="icon">http://example.com/img.png</span></a></td><td>text
++</td></tr></table>
++------------------------------
++||<a class="ext-link" href="http://example.com/img.png";><span class="icon">http://example.com/img.png</span></a>||text||
++============================== Link resolver, long form with quoting
++[link:WikiStart Foo] [http://www.edgewall.com/ Edgewall]
++
++link:"Foo Bar" link:"Foo Bar#baz"
++
++[link:"Foo Bar" Foo Bar] [link:"Foo Bar#baz" Foo Bar]
++
++[link:Argv "*argv[] versus **argv"]
++
++[link:test "test.txt", line 123]
++
++[link:pl/de %de]
++------------------------------
++<p>
++<a class="text resolver" href="/stuff/WikiStart">Foo</a> <a class="ext-link" href="http://www.edgewall.com/";><span class="icon">Edgewall</span></a>
++</p>
++<p>
++<a class="text resolver" href="/stuff/Foo%20Bar">link:"Foo Bar"</a> <a class="text resolver" href="/stuff/Foo%20Bar%23baz">link:"Foo Bar#baz"</a>
++</p>
++<p>
++<a class="text resolver" href="/stuff/Foo%20Bar">Foo Bar</a> <a class="text resolver" href="/stuff/Foo%20Bar%23baz">Foo Bar</a>
++</p>
++<p>
++<a class="text resolver" href="/stuff/Argv">*argv[] versus **argv</a>
++</p>
++<p>
++<a class="text resolver" href="/stuff/test">"test.txt", line 123</a>
++</p>
++<p>
++<a class="text resolver" href="/stuff/pl/de">%de</a>
++</p>
++------------------------------
++============================== Link resolver in markup
++'''link:1''', ''link:1'', ~~link:1~~, __link:1__
++------------------------------
++<p>
++<strong><a class="odd resolver" href="/thing/1">link:1</a></strong>, <i><a class="odd resolver" href="/thing/1">link:1</a></i>, <del><a class="odd resolver" href="/thing/1">link:1</a></del>, <span class="underline"><a class="odd resolver" href="/thing/1">link:1</a></span>
++</p>
++------------------------------
++============================== Link resolver, quoting of target
++link:1
++link:12
++link:123
++link:'1'
++link:'12'
++link:'123'
++link:"1"
++link:"12"
++link:"123"
++------------------------------
++<p>
++<a class="odd resolver" href="/thing/1">link:1</a>
++<a class="even resolver" href="/thing/12">link:12</a>
++<a class="odd resolver" href="/thing/123">link:123</a>
++<a class="odd resolver" href="/thing/1">link:'1'</a>
++<a class="even resolver" href="/thing/12">link:'12'</a>
++<a class="odd resolver" href="/thing/123">link:'123'</a>
++<a class="odd resolver" href="/thing/1">link:"1"</a>
++<a class="even resolver" href="/thing/12">link:"12"</a>
++<a class="odd resolver" href="/thing/123">link:"123"</a>
++</p>
++------------------------------
++============================== Link resolver look alike, quoting of target
++nolink:"<blink>"
++------------------------------
++<p>
++nolink:&#34;&lt;blink&gt;&#34;
++</p>
++------------------------------
++============================================================
++
++        Other Links
++
++============================== Relative links
++Relative links are supported:
++[../parent See above] Note: see wikisyntax tests for other parent tests
++[./sibling See next]
++[... nothing to see] [...]
++[//docs See documentation]
++[//images/logo.png Our logo]
++[/] Note: "" is an Href("/") artifact
++[/newticket?component=test new ticket]
++[#title]
++[#title see Title]
++------------------------------
++<p>
++Relative links are supported:
++<a href="/wiki/parent">See above</a> Note: see wikisyntax tests for other parent tests
++<a href="/wiki/WikiStart/sibling">See next</a>
++[... nothing to see] [...]
++<a href="/docs">See documentation</a>
++<a href="/images/logo.png">Our logo</a>
++<a href="">/</a> Note: "" is an Href("/") artifact
++<a href="/newticket?component=test">new ticket</a>
++<a href="/wiki/WikiStart#title">#title</a>
++<a href="/wiki/WikiStart#title">see Title</a>
++</p>
++------------------------------
++==============================  Image links are now regular external links
++http://example.com/img.png?foo=bar
++------------------------------
++<p>
++<a class="ext-link" href="http://example.com/img.png?foo=bar";><span class="icon">http://example.com/img.png?foo=bar</span></a>
++</p>
++------------------------------
++<a class="ext-link" href="http://example.com/img.png?foo=bar";><span class="icon">http://example.com/img.png?foo=bar</span></a>
++============================== Arbitrary protocol Link
++''RFCs von ftp://ftp.rfc-editor.org/in-notes/rfcXXXX.txt''
++------------------------------
++<p>
++<i>RFCs von <a class="ext-link" href="ftp://ftp.rfc-editor.org/in-notes/rfcXXXX.txt";><span class="icon">ftp://ftp.rfc-editor.org/in-notes/rfcXXXX.txt</span></a></i>
++</p>
++------------------------------
++==============================  mailto: links and automatic e-mail detection
++Author: mailto:cboos@neuf.fr, 
++i.e. [mailto:cboos@neuf.fr me]
++
++joe'bar@site.info,
++trac+devel@another-site.fr,
++T_r=a-c1.23@yet_another-site.edu.au
++!not@an.email.com
++someone@louvre.museum-
++------------------------------
++<p>
++Author: <a class="mail-link" href="mailto:cboos@neuf.fr";><span class="icon">mailto:cboos@neuf.fr</span></a>, 
++i.e. <a class="mail-link" href="mailto:cboos@neuf.fr";><span class="icon">me</span></a>
++</p>
++<p>
++<a class="mail-link" href="mailto:joe'bar@site.info"><span class="icon">joe'bar@site.info</span></a>,
++<a class="mail-link" href="mailto:trac+devel@another-site.fr";><span class="icon">trac+devel@another-site.fr</span></a>,
++<a class="mail-link" href="mailto:T_r=a-c1.23@yet_another-site.edu.au";><span class="icon">T_r=a-c1.23@yet_another-site.edu.au</span></a>
++not@an.email.com
++<a class="mail-link" href="mailto:someone@louvre.museum";><span class="icon">someone@louvre.museum</span></a>-
++</p>
++------------------------------
++============================== Arbitrary protocol Link
++''RFCs von ftp://ftp.rfc-editor.org/in-notes/rfcXXXX.txt''
++------------------------------
++<p>
++<i>RFCs von <a class="ext-link" href="ftp://ftp.rfc-editor.org/in-notes/rfcXXXX.txt";><span class="icon">ftp://ftp.rfc-editor.org/in-notes/rfcXXXX.txt</span></a></i>
++</p>
++------------------------------
++============================== Generic InterTrac links
++th:roadmap
++th:roadmap:
++[th:]
++[th: Trac Hacks]
++------------------------------
++<p>
++<a class="ext-link" href="http://trac-hacks.org/intertrac/roadmap"; title="roadmap in Trac Hacks"><span class="icon">th:roadmap</span></a>
++<a class="ext-link" href="http://trac-hacks.org/intertrac/roadmap"; title="roadmap in Trac Hacks"><span class="icon">th:roadmap</span></a>:
++<a class="ext-link" href="http://trac-hacks.org/intertrac/"; title="Trac Hacks"><span class="icon">th</span></a>
++<a class="ext-link" href="http://trac-hacks.org/intertrac/"; title="Trac Hacks"><span class="icon">Trac Hacks</span></a>
++</p>
++------------------------------
++============================== Another arbitrary protocol Link
++svn+ssh://secureserver.org
++[svn+ssh://secureserver.org SVN link]
++rfc-2396.compatible://link
++[rfc-2396.compatible://link RFC 2396]
++------------------------------
++<p>
++<a class="ext-link" href="svn+ssh://secureserver.org"><span class="icon">svn+ssh://secureserver.org</span></a>
++<a class="ext-link" href="svn+ssh://secureserver.org"><span class="icon">SVN link</span></a>
++<a class="ext-link" href="rfc-2396.compatible://link"><span class="icon">rfc-2396.compatible://link</span></a>
++<a class="ext-link" href="rfc-2396.compatible://link"><span class="icon">RFC 2396</span></a>
++</p>
++------------------------------
++============================== Link resolver counter examples
++Test:[[BR]] There should be a line break
++
++Other test:'''bold text''' should be bold
++------------------------------
++<p>
++Test:<br /> There should be a line break
++</p>
++<p>
++Other test:<strong>bold text</strong> should be bold
++</p>
++------------------------------
++Test:  There should be a line break
++
++Other test:<strong>bold text</strong> should be bold
++============================== Link resolver counter example
++'''Note:'''
++------------------------------
++<p>
++<strong>Note:</strong>
++</p>
++------------------------------
++<strong>Note:</strong>
++==============================
++============================================================
++
++        Processor blocks
++
++============================== Code Block 1
++{{{
++Preformatted text.
++}}}
++Paragraph
++------------------------------
++<pre class="wiki">Preformatted text.
++</pre><p>
++Paragraph
++</p>
++------------------------------
++ […]
++Paragraph
++============================== Code Block 2
++{{{
++<b>Preformatted text</b>.
++}}}
++Paragraph
++------------------------------
++<pre class="wiki">&lt;b&gt;Preformatted text&lt;/b&gt;.
++</pre><p>
++Paragraph
++</p>
++------------------------------
++ […]
++Paragraph
++============================== Embedded code blocks
++{{{
++Outer block.
++{{{
++Inner block.
++}}}
++}}}
++Paragraph
++------------------------------
++<pre class="wiki">Outer block.
++{{{
++Inner block.
++}}}
++</pre><p>
++Paragraph
++</p>
++------------------------------
++ […]
++Paragraph
++============================== Consecutive code blocks
++Block 
++{{{
++number one
++}}}
++and block
++{{{
++number two
++}}}
++.
++------------------------------
++<p>
++Block 
++</p>
++<pre class="wiki">number one
++</pre><p>
++and block
++</p>
++<pre class="wiki">number two
++</pre><p>
++.
++</p>
++------------------------------
++Block 
++ […]
++and block
++ […]
++.
++============================== Unfinished code blocks
++Block 
++{{{
++number one
++
++and block
++{{{
++number two
++ }}
++------------------------------
++<p>
++Block 
++</p>
++<pre class="wiki">number one
++
++and block
++{{{
++number two
++ }}
++}}}
++</pre>------------------------------
++Block […]
++============================== Wiki processor
++{{{
++#!default
++Preformatted text.
++}}}
++Paragraph
++------------------------------
++<pre class="wiki">Preformatted text.
++</pre><p>
++Paragraph
++</p>
++------------------------------
++ […]
++Paragraph
++============================== Wiki processor counter example
++{{{
++#!/bin/sh
++echo "foo"
++}}}
++Paragraph
++------------------------------
++<pre class="wiki">#!/bin/sh
++echo "foo"
++</pre><p>
++Paragraph
++</p>
++------------------------------
++ […]
++Paragraph
++============================== HTML wiki processor
++{{{
++#!html
++<p>Hello World</p>
++}}}
++------------------------------
++<p>Hello World</p>
++------------------------------
++ […]
++============================== HTML wiki processor, XSS check 1
++{{{
++#!html
++<script>alert("");</script>
++}}}
++------------------------------
++
++------------------------------
++ […]
++============================== HTML wiki processor, XSS check 2
++{{{
++#!html
++<div onclick="alert('')">Click me</div>
++}}}
++------------------------------
++<div>Click me</div>
++------------------------------
++ […]
++============================== div and span wiki processors
++And now it's [[span('''TIME FOR BED!,class=important)]]. Really.
++{{{
++#!div ; class=important
++Go ahead, edit it freely.
++
++{{{
++#!div; style="border: 2pt solid blue; margin: 1em; padding: .5em"; class=demo
++And now it's [[span('''TIME FOR BED! ''',class=important)]]. Really.
++}}}
++etc.
++}}}
++Done.
++------------------------------
++<p>
++And now it's <span class="important"><strong>TIME FOR BED!</strong></span>. Really.
++</p>
++<div class="important"><p>
++Go ahead, edit it freely.
++</p>
++<div style="border: 2pt solid blue; margin: 1em; padding: .5em" class="demo"><p>
++And now it's <span class="important"><strong>TIME FOR BED! </strong></span>. Really.
++</p>
++</div><p>
++etc.
++</p>
++</div><p>
++Done.
++</p>
++------------------------------
++And now it's [[span(...)]]. Really.
++ […]
++Done.
++============================== div and Span wiki processors
++{{{
++#!div ; class="important"
++Go ahead, [[Span(''edit it freely'',class=important)]].
++}}}
++Done.
++------------------------------
++<div class="important"><p>
++Go ahead, <span class="important"><i>edit it freely</i></span>.
++</p>
++</div><p>
++Done.
++</p>
++------------------------------
++ […]
++Done.
++============================================================
++
++        Wiki Macros
++
++============================== Macro with arguments (leading)
++[[HelloWorld(hej hopp)]]
++------------------------------
++<p>
++Hello World, args = hej hopp
++</p>
++------------------------------
++[[HelloWorld(...)]]
++============================== Macro with arguments (in flow)
++Hello, [[HelloWorld(hej hopp)]]
++------------------------------
++<p>
++Hello, Hello World, args = hej hopp
++</p>
++------------------------------
++Hello, [[HelloWorld(...)]]
++============================== Bad macro call
++[[HelloWorld(hej hopp) ]] # This shouldnt executed as macro since it contain whitespace between ) and ]
++------------------------------
++<p>
++[[<a class="missing wiki" href="/wiki/HelloWorld" rel="nofollow">HelloWorld?</a>(hej hopp) ]] # This shouldnt executed as macro since it contain whitespace between ) and ]
++</p>
++------------------------------
++[[<a class="missing wiki" href="/wiki/HelloWorld" rel="nofollow">HelloWorld?</a>(hej hopp) ]] # This shouldnt executed as macro since it contain whitespace between ) and ]
++============================== Another bad macro call
++[[HelloWorld(hej hopp))]] # Extra right brace and still executed
++------------------------------
++<p>
++Hello World, args = hej hopp) # Extra right brace and still executed
++</p>
++------------------------------
++[[HelloWorld(...)]] # Extra right brace and still executed
++============================== Two consecutive macros on a line
++[[HelloWorld(hej hopp)]] [[HelloWorld(hej hopp2)]] # Test non greedy match
++------------------------------
++<p>
++Hello World, args = hej hopp Hello World, args = hej hopp2 # Test non greedy match
++</p>
++------------------------------
++[[HelloWorld(...)]] [[HelloWorld(...)]] # Test non greedy match
++============================== Macro returning a <div>
++[[DivHelloWorld(hej hopp)]]
++------------------------------
++<p>
++</p><div>Hello World, args = hej hopp</div><p>
++</p>
++------------------------------
++[[DivHelloWorld(...)]]
++============================== Macro returning a <div class="...code...">
++[[DivCode(hej hopp)]]
++------------------------------
++<p>
++<span class="code-block">Hello World, args = hej hopp</span>
++</p>
++------------------------------
++[[DivCode(...)]]
++============================== Macro returning an html.DIV(class="...code...">)
++[[DivCodeElement(hej hopp)]]
++------------------------------
++<p>
++<span class="code-block">Hello World, args = hej hopp</span>
++</p>
++------------------------------
++[[DivCodeElement(...)]]
++============================== Macro returning a Genshi Stream (no "code" div)
++[[DivCodeStream(hej hopp)]]
++------------------------------
++<p>
++</p><div>Hello World, args = hej hopp</div><p>
++</p>
++------------------------------
++[[DivCodeStream(...)]]
++============================== Macro returning None
++[[None(hej hopp)]] nada
++------------------------------
++<p>
++ nada
++</p>
++------------------------------
++[[None(...)]] nada
++============================== Inlined HTML wiki processor
++Inline [[html(<B> Test </B>)]] text
++------------------------------
++<p>
++Inline <b> Test </b> text
++</p>
++------------------------------
++Inline [[html(...)]] text
++============================== BR macro
++Line break [[BR]] another line[[br]]last line
++------------------------------
++<p>
++Line break <br /> another line<br />last line
++</p>
++------------------------------
++Line break   another line last line
++============================== Comment wiki processor
++Test comment blocks
++{{{
++#!comment
++This is simply removed from the output
++}}}
++------------------------------
++<p>
++Test comment blocks
++</p>
++------------------------------
++Test comment blocks
++============================== Comment wiki processor called as a macro
++Inline [[comment(This should not be seen)]] comment
++------------------------------
++<p>
++Inline  comment
++</p>
++------------------------------
++Inline  comment
++============================================================
++
++           Headings
++
++============================== I18N heading
++= ça marche! =
++------------------------------
++<h1 id="çamarche">ça marche!</h1>
++------------------------------
++= ça marche! =
++============================== Quoted heading
++= "Test" =
++------------------------------
++<h1 id="Test">"Test"</h1>
++------------------------------
++= "Test" =
++============================== Heading with < and >
++= Foo <Bar> Baz =
++------------------------------
++<h1 id="FooBarBaz">Foo &lt;Bar&gt; Baz</h1>
++------------------------------
++= Foo &lt;Bar&gt; Baz =
++============================== Heading with .
++= Version 0.10 =
++------------------------------
++<h1 id="Version0.10">Version 0.10</h1>
++------------------------------
++= Version 0.10 =
++============================== Normal heading
++== Heading with trailing white-space == 
++------------------------------
++<h2 id="Headingwithtrailingwhite-space">Heading with trailing white-space</h2>
++------------------------------
++== Heading with trailing white-space ==
++============================== Formatted heading
++== ''Formatted'' ~~Heading~~ ==
++------------------------------
++<h2 id="FormattedHeading"><i>Formatted</i> <del>Heading</del></h2>
++------------------------------
++== ''Formatted'' ~~Heading~~ ==
++============================== Heading with link
++== [wiki:SandBox Linked Heading] ==
++------------------------------
++<h2 id="LinkedHeading"><a class="missing wiki" href="/wiki/SandBox" rel="nofollow">Linked Heading?</a></h2>
++------------------------------
++== [wiki:SandBox Linked Heading] ==
++============================== Normal heading, fixed id
++== Heading with fixed id == #heading-fixed-id
++------------------------------
++<h2 id="heading-fixed-id">Heading with fixed id</h2>
++------------------------------
++== Heading with fixed id == #heading-fixed-id
++============================== Normal heading, auto-corrected id
++== 10 tips ==
++------------------------------
++<h2 id="a10tips">10 tips</h2>
++------------------------------
++== 10 tips ==
++============================================================
++
++             Lists
++
++============================== Bulleted lists
++Paragraph
++ * foo bar
++   boo baz
++   * Subitem
++     Subitem line 2
++ * item 2
++   item 2 line 2
++Paragraph
++------------------------------
++<p>
++Paragraph
++</p>
++<ul><li>foo bar
++boo baz
++<ul><li>Subitem
++Subitem line 2
++</li></ul></li><li>item 2
++item 2 line 2
++</li></ul><p>
++Paragraph
++</p>
++------------------------------
++Paragraph
++ * foo bar
++   boo baz
++   * Subitem
++     Subitem line 2
++ * item 2
++   item 2 line 2
++Paragraph
++============================== Changelog sample (and e-mail link)
++2003-09-18 23:26  Joe Bar <joeb@gloogle.gom>
++
++	* src/code.py: Fix problem with obsolete use of
++	backslash in symbols.
++        * src/test.py: Added unit tests.
++          - test + symbol
++          - test - symbol
++Paragraph
++------------------------------
++<p>
++2003-09-18 23:26  Joe Bar &lt;<a class="mail-link" href="mailto:joeb@gloogle.gom";><span class="icon">joeb@gloogle.gom</span></a>&gt;
++</p>
++<ul><li>src/code.py: Fix problem with obsolete use of
++backslash in symbols.
++</li><li>src/test.py: Added unit tests.
++<ul><li>test + symbol
++</li><li>test - symbol
++</li></ul></li></ul><p>
++Paragraph
++</p>
++------------------------------
++============================== Complex bulleted list
++    * foo bar
++      boo baz
++           * Subitem 1
++             - nested item 1
++             - nested item 2
++             nested item 2 continued
++           Subitem 1 continued
++        * Subitem 2
++         Subitem 2 continued
++        * Subitem 3
++          continued
++    * item 2
++     item 2 line 2
++Paragraph
++------------------------------
++<ul><li>foo bar
++boo baz
++<ul><li>Subitem 1
++<ul><li>nested item 1
++</li><li>nested item 2
++nested item 2 continued
++</li></ul></li><li>Subitem 1 continued
++</li></ul></li><li>Subitem 2
++Subitem 2 continued
++</li><li>Subitem 3
++continued
++</li></ul><ul><li>item 2
++item 2 line 2
++</li></ul><p>
++Paragraph
++</p>
++------------------------------
++============================== Numbered lists
++ 1. item 1
++   a. item 1.a
++   a. item 1.b
++
++Some paragraph
++
++ 2. continue with item 2
++    i. roman 1
++    ii. roman 2
++Paragraph
++------------------------------
++<ol><li>item 1
++<ol class="loweralpha"><li>item 1.a
++</li><li>item 1.b
++</li></ol></li></ol><p>
++Some paragraph
++</p>
++<ol start="2"><li>continue with item 2
++<ol class="lowerroman"><li>roman 1
++</li><li>roman 2
++</li></ol></li></ol><p>
++Paragraph
++</p>
++------------------------------
++1. item 1
++   a. item 1.a
++   a. item 1.b
++
++Some paragraph
++
++ 2. continue with item 2
++    i. roman 1
++    ii. roman 2
++Paragraph
++============================== Numbered lists multi-line items
++ 1. This is a very long line at
++    the first level, which works correctly.
++    1. But this line at the second level, which
++       is also continued on the next line, does not.
++Paragraph
++------------------------------
++<ol><li>This is a very long line at
++the first level, which works correctly.
++<ol><li>But this line at the second level, which
++is also continued on the next line, does not.
++</li></ol></li></ol><p>
++Paragraph
++</p>
++------------------------------
++1. This is a very long line at
++    the first level, which works correctly.
++    1. But this line at the second level, which
++       is also continued on the next line, does not.
++Paragraph
++============================== Numbered lists counter-examples
++ This will not start a new numbered
++ list. There's more than one character
++ before the "."
++ OTOH, the following is a roman numbered list:
++ iii. start
++ xxvii. maximal number in sequence
++Paragraph
++------------------------------
++<blockquote>
++<p>
++This will not start a new numbered
++list. There's more than one character
++before the "."
++OTOH, the following is a roman numbered list:
++</p>
++</blockquote>
++<ol class="lowerroman"><li>start
++</li><li>maximal number in sequence
++</li></ol><p>
++Paragraph
++</p>
++------------------------------
++============================== Mixed lists multi-line items
++ 1. multi-line
++    numbered list
++    i. multi-line
++      item i.
++      * sub item
++    ii. multi-line
++      item ii.
++      * sub item
++        multiline
++        a. subsub
++          multiline
++        b. subsub
++    iii. multi-line
++      item iii.
++      * sub item
++Paragraph
++------------------------------
++<ol><li>multi-line
++numbered list
++<ol class="lowerroman"><li>multi-line
++item i.
++<ul><li>sub item
++</li></ul></li><li>multi-line
++item ii.
++<ul><li>sub item
++multiline
++<ol class="loweralpha"><li>subsub
++multiline
++</li><li>subsub
++</li></ol></li></ul></li><li>multi-line
++item iii.
++<ul><li>sub item
++</li></ul></li></ol></li></ol><p>
++Paragraph
++</p>
++------------------------------
++============================== Simple definition list
++ term:: definition
++------------------------------
++<dl><dt>term</dt><dd>definition
++</dd></dl>
++------------------------------
++term:: definition
++============================== Tricky definition list
++ term:: definition:: text
++------------------------------
++<dl><dt>term</dt><dd>definition:: text
++</dd></dl>
++------------------------------
++term:: definition:: text
++============================== Verbatim term in definition list
++ `term`:: definition
++------------------------------
++<dl><dt><tt>term</tt></dt><dd>definition
++</dd></dl>
++------------------------------
++<tt>term</tt>:: definition
++============================== Another verbatim term in definition list
++ {{{term}}}:: definition
++------------------------------
++<dl><dt><tt>term</tt></dt><dd>definition
++</dd></dl>
++------------------------------
++<tt>term</tt>:: definition
++============================== Complex definition list
++ complex topic:: multiline
++                 ''formatted''
++                 definition
++------------------------------
++<dl><dt>complex topic</dt><dd>multiline
++<i>formatted</i>
++definition
++</dd></dl>
++------------------------------
++complex topic:: multiline
++                 <i>formatted</i>
++                 definition
++============================== Definition list counter example
++ term::definition
++------------------------------
++<blockquote>
++<p>
++term::definition
++</p>
++</blockquote>
++------------------------------
++term::definition
++============================== Definition list + escaped definition list
++ complex topic:: multiline
++                 `not:: a dl`
++------------------------------
++<dl><dt>complex topic</dt><dd>multiline
++<tt>not:: a dl</tt>
++</dd></dl>
++------------------------------
++complex topic:: multiline
++                 <tt>not:: a dl</tt>
++============================== Definition list + another escaped definition list
++ complex topic:: multiline
++                 {{{not:: a dl}}}
++------------------------------
++<dl><dt>complex topic</dt><dd>multiline
++<tt>not:: a dl</tt>
++</dd></dl>
++------------------------------
++complex topic:: multiline
++                 <tt>not:: a dl</tt>
++============================================================
++
++            Tables
++
++============================== Simple Table, one column
++|| a || 
++|| b ||
++------------------------------
++<table class="wiki">
++<tr><td> a 
++</td></tr><tr><td> b 
++</td></tr></table>
++------------------------------
++|| a || 
++|| b ||
++============================== Simple Table, multiple columns
++in:
++|| RPC# || parameter len || ..... parameter ..... ||
++out:
++|| RPC# || parameter len || ..... parameter ..... ||
++----
++------------------------------
++<p>
++in:
++</p>
++<table class="wiki">
++<tr><td> RPC# </td><td> parameter len </td><td> ..... parameter ..... 
++</td></tr></table>
++<p>
++out:
++</p>
++<table class="wiki">
++<tr><td> RPC# </td><td> parameter len </td><td> ..... parameter ..... 
++</td></tr></table>
++<hr />
++------------------------------
++in:
++|| RPC# || parameter len || ..... parameter ..... ||
++out:
++|| RPC# || parameter len || ..... parameter ..... ||
++----
++============================== Indented tables, multiple columns
++|| a || b ||
++
++  || a || b ||
++  || a || b ||
++
++|| a || b ||
++------------------------------
++<table class="wiki">
++<tr><td> a </td><td> b 
++</td></tr></table>
++<blockquote>
++<table class="wiki">
++<tr><td> a </td><td> b 
++</td></tr><tr><td> a </td><td> b 
++</td></tr></table>
++</blockquote>
++<table class="wiki">
++<tr><td> a </td><td> b 
++</td></tr></table>
++------------------------------
++|| a || b ||
++
++  || a || b ||
++  || a || b ||
++
++|| a || b ||
++============================================================
++
++         Mixed examples
++
++============================== Mix of headings and lists
++= Heading 1 =
++Paragraph
++ * Item 1
++   * Item 2
++Another paragraph
++------------------------------
++<h1 id="Heading1">Heading 1</h1>
++<p>
++Paragraph
++</p>
++<ul><li>Item 1
++<ul><li>Item 2
++</li></ul></li></ul><p>
++Another paragraph
++</p>
++------------------------------
++= Heading 1 =
++Paragraph
++ * Item 1
++   * Item 2
++Another paragraph
++============================== Heading, lists and table
++Paragraph
++----
++ 1. Item 1
++   2. Item 2
++||Table||cell||
++||Foo||Bar||Baz||
++http://www.edgewall.com/
++------------------------------
++<p>
++Paragraph
++</p>
++<hr />
++<ol><li>Item 1
++<ol start="2"><li>Item 2
++</li></ol></li></ol><table class="wiki">
++<tr><td>Table</td><td>cell
++</td></tr><tr><td>Foo</td><td>Bar</td><td>Baz
++</td></tr></table>
++<p>
++<a class="ext-link" href="http://www.edgewall.com/";><span class="icon">http://www.edgewall.com/</span></a>
++</p>
++------------------------------
++Paragraph
++----
++ 1. Item 1
++   2. Item 2
++||Table||cell||
++||Foo||Bar||Baz||
++<a class="ext-link" href="http://www.edgewall.com/";><span class="icon">http://www.edgewall.com/</span></a>
++============================== Lists, indents and table
++
++  * Bar
++    * Foo
++
++    || Foo || Bar ||
++
++  || Foo || Bar ||
++------------------------------
++<ul><li>Bar
++<ul><li>Foo
++</li></ul></li></ul><blockquote>
++<blockquote>
++<table class="wiki">
++<tr><td> Foo </td><td> Bar 
++</td></tr></table>
++</blockquote>
++</blockquote>
++<blockquote>
++<table class="wiki">
++<tr><td> Foo </td><td> Bar 
++</td></tr></table>
++</blockquote>
++------------------------------
++* Bar
++    * Foo
++
++    || Foo || Bar ||
++
++  || Foo || Bar ||
++============================== "Tabstops" set by lists and quotes
++        This is one level deep
++
++  * Bar
++        * Foo
++
++        Now this should be 2 levels deep as well
++
++               This is now level 3.
++
++        Continue on level 2.
++
++          - but a list always restart at level 1.
++Paragraph.
++------------------------------
++<blockquote>
++<p>
++This is one level deep
++</p>
++</blockquote>
++<ul><li>Bar
++<ul><li>Foo
++</li></ul></li></ul><blockquote>
++<blockquote>
++<p>
++Now this should be 2 levels deep as well
++</p>
++</blockquote>
++</blockquote>
++<blockquote>
++<blockquote>
++<blockquote>
++<p>
++This is now level 3.
++</p>
++</blockquote>
++</blockquote>
++</blockquote>
++<blockquote>
++<blockquote>
++<p>
++Continue on level 2.
++</p>
++</blockquote>
++</blockquote>
++<ul><li>but a list always restart at level 1.
++</li></ul><p>
++Paragraph.
++</p>
++------------------------------
++============================== Citations
++> This is the quoted text
++>> a nested quote
++A comment on the above
++>> start 2nd level
++> first level
++------------------------------
++<blockquote class="citation">
++<p>
++ This is the quoted text
++</p>
++<blockquote class="citation">
++<p>
++ a nested quote
++</p>
++</blockquote>
++</blockquote>
++<p>
++A comment on the above
++</p>
++<blockquote class="citation">
++<blockquote class="citation">
++<p>
++ start 2nd level
++</p>
++</blockquote>
++<p>
++ first level
++</p>
++</blockquote>
++------------------------------
++&gt; This is the quoted text
++&gt;&gt; a nested quote
++A comment on the above
++&gt;&gt; start 2nd level
++&gt; first level

Reply to: