changeset 4301:c689dfa55de1

Import werkzeug 0.3.1 package into MoinMoin.support (still need to insert CREDITS)
author Florian Krupicka <florian.krupicka@googlemail.com>
date Wed, 13 Aug 2008 21:05:42 +0200
parents 867da7983aba
children 775e8f24c1b1
files MoinMoin/support/werkzeug/__init__.py MoinMoin/support/werkzeug/_internal.py MoinMoin/support/werkzeug/contrib/__init__.py MoinMoin/support/werkzeug/contrib/atom.py MoinMoin/support/werkzeug/contrib/cache.py MoinMoin/support/werkzeug/contrib/iterio.py MoinMoin/support/werkzeug/contrib/jsrouting.py MoinMoin/support/werkzeug/contrib/kickstart.py MoinMoin/support/werkzeug/contrib/limiter.py MoinMoin/support/werkzeug/contrib/profiler.py MoinMoin/support/werkzeug/contrib/reporterstream.py MoinMoin/support/werkzeug/contrib/securecookie.py MoinMoin/support/werkzeug/contrib/sessions.py MoinMoin/support/werkzeug/contrib/testtools.py MoinMoin/support/werkzeug/debug/__init__.py MoinMoin/support/werkzeug/debug/console.py MoinMoin/support/werkzeug/debug/render.py MoinMoin/support/werkzeug/debug/repr.py MoinMoin/support/werkzeug/debug/shared/body.tmpl MoinMoin/support/werkzeug/debug/shared/codetable.tmpl MoinMoin/support/werkzeug/debug/shared/console.png MoinMoin/support/werkzeug/debug/shared/debugger.js MoinMoin/support/werkzeug/debug/shared/jquery.js MoinMoin/support/werkzeug/debug/shared/less.png MoinMoin/support/werkzeug/debug/shared/more.png MoinMoin/support/werkzeug/debug/shared/source.png MoinMoin/support/werkzeug/debug/shared/style.css MoinMoin/support/werkzeug/debug/shared/vartable.tmpl MoinMoin/support/werkzeug/debug/tbtools.py MoinMoin/support/werkzeug/debug/templates/console.html MoinMoin/support/werkzeug/debug/templates/dump_object.html MoinMoin/support/werkzeug/debug/templates/frame.html MoinMoin/support/werkzeug/debug/templates/help_command.html MoinMoin/support/werkzeug/debug/templates/source.html MoinMoin/support/werkzeug/debug/templates/traceback_full.html MoinMoin/support/werkzeug/debug/templates/traceback_plaintext.html MoinMoin/support/werkzeug/debug/templates/traceback_summary.html MoinMoin/support/werkzeug/debug/utils.py MoinMoin/support/werkzeug/exceptions.py MoinMoin/support/werkzeug/http.py MoinMoin/support/werkzeug/local.py MoinMoin/support/werkzeug/routing.py MoinMoin/support/werkzeug/script.py MoinMoin/support/werkzeug/serving.py MoinMoin/support/werkzeug/templates.py MoinMoin/support/werkzeug/test.py MoinMoin/support/werkzeug/testapp.py MoinMoin/support/werkzeug/useragents.py MoinMoin/support/werkzeug/utils.py MoinMoin/support/werkzeug/wrappers.py
diffstat 50 files changed, 11655 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/__init__.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,99 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug
+    ~~~~~~~~
+
+    Werkzeug is the Swiss Army knife of Python web development.
+
+    It provides useful classes and functions for any WSGI application to make
+    the life of a python web developer much easier.  All of the provided
+    classes are independed from each other so you can mix it with any other
+    library.
+
+
+    :copyright: 2007-2008 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+from types import ModuleType
+import sys
+
+
+all_by_module = {
+    'werkzeug.debug':       ['DebuggedApplication'],
+    'werkzeug.local':       ['Local', 'LocalManager', 'LocalProxy'],
+    'werkzeug.templates':   ['Template'],
+    'werkzeug.serving':     ['run_simple'],
+    'werkzeug.test':        ['Client'],
+    'werkzeug.testapp':     ['test_app'],
+    'werkzeug.exceptions':  ['abort', 'Aborter'],
+    'werkzeug.utils':       ['escape', 'create_environ', 'url_quote',
+                             'environ_property', 'cookie_date', 'http_date',
+                             'url_encode', 'url_quote_plus', 'Headers',
+                             'EnvironHeaders', 'CombinedMultiDict', 'url_fix',
+                             'run_wsgi_app', 'get_host', 'responder',
+                             'SharedDataMiddleware', 'ClosingIterator',
+                             'FileStorage', 'url_unquote_plus', 'url_decode',
+                             'url_unquote', 'get_current_url', 'redirect',
+                             'append_slash_redirect',
+                             'cached_property', 'MultiDict', 'import_string',
+                             'dump_cookie', 'parse_cookie', 'unescape',
+                             'format_string', 'Href', 'DispatcherMiddleware',
+                             'find_modules', 'header_property', 'html',
+                             'xhtml', 'HTMLBuilder', 'parse_form_data',
+                             'validate_arguments', 'ArgumentValidationError',
+                             'bind_arguments'],
+    'werkzeug.useragents':  ['UserAgent'],
+    'werkzeug.http':        ['Accept', 'CacheControl', 'ETags', 'parse_etags',
+                             'parse_date', 'parse_cache_control_header',
+                             'is_resource_modified', 'parse_accept_header',
+                             'parse_set_header', 'quote_etag', 'unquote_etag',
+                             'generate_etag', 'dump_header',
+                             'parse_list_header', 'parse_dict_header',
+                             'HeaderSet', 'parse_authorization_header',
+                             'parse_www_authenticate_header',
+                             'WWWAuthenticate', 'Authorization',
+                             'HTTP_STATUS_CODES'],
+    'werkzeug.wrappers':    ['BaseResponse', 'BaseRequest', 'Request',
+                             'Response', 'AcceptMixin', 'ETagRequestMixin',
+                             'ETagResponseMixin', 'ResponseStreamMixin',
+                             'CommonResponseDescriptorsMixin',
+                             'UserAgentMixin', 'AuthorizationMixin',
+                             'WWWAuthenticateMixin'],
+    # the undocumented easteregg ;-)
+    'werkzeug._internal':   ['_easteregg']
+}
+
+attribute_modules = dict.fromkeys(['exceptions', 'routing', 'script'])
+
+
+object_origins = {}
+for module, items in all_by_module.iteritems():
+    for item in items:
+        object_origins[item] = module
+
+
+class module(ModuleType):
+    """Automatically import objects from the modules."""
+
+    def __getattr__(self, name):
+        if name in object_origins:
+            module = __import__(object_origins[name], None, None, [name])
+            for extra_name in all_by_module[module.__name__]:
+                setattr(self, extra_name, getattr(module, extra_name))
+            return getattr(module, name)
+        elif name in attribute_modules:
+            __import__('werkzeug.' + name)
+        return ModuleType.__getattribute__(self, name)
+
+
+# keep a reference to this module so that it's not garbage collected
+old_module = sys.modules['werkzeug']
+
+# setup the new module and patch it into the dict of loaded modules
+new_module = sys.modules['werkzeug'] = module('werkzeug')
+new_module.__dict__.update({
+    '__file__': __file__,
+    '__path__': __path__,
+    '__doc__':  __doc__,
+    '__all__':  tuple(object_origins) + tuple(attribute_modules)
+})
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/_internal.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,407 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug._internal
+    ~~~~~~~~~~~~~~~~~~
+
+    This module provides internally used helpers and constants.
+
+    :copyright: Copyright 2008 by Armin Ronacher.
+    :license: GNU GPL.
+"""
+import cgi
+import inspect
+from weakref import WeakKeyDictionary
+from cStringIO import StringIO
+from Cookie import BaseCookie, Morsel, CookieError
+from time import asctime, gmtime, time
+from datetime import datetime
+
+
+_logger = None
+_empty_stream = StringIO('')
+_signature_cache = WeakKeyDictionary()
+
+
+HTTP_STATUS_CODES = {
+    100:    'Continue',
+    101:    'Switching Protocols',
+    102:    'Processing',
+    200:    'OK',
+    201:    'Created',
+    202:    'Accepted',
+    203:    'Non Authoritative Information',
+    204:    'No Content',
+    205:    'Reset Content',
+    206:    'Partial Content',
+    207:    'Multi Status',
+    226:    'IM Used',              # see RFC 3229
+    300:    'Multiple Choices',
+    301:    'Moved Permanently',
+    302:    'Found',
+    303:    'See Other',
+    304:    'Not Modified',
+    305:    'Use Proxy',
+    307:    'Temporary Redirect',
+    400:    'Bad Request',
+    401:    'Unauthorized',
+    402:    'Payment Required',     # unused
+    403:    'Forbidden',
+    404:    'Not Found',
+    405:    'Method Not Allowed',
+    406:    'Not Acceptable',
+    407:    'Proxy Authentication Required',
+    408:    'Request Timeout',
+    409:    'Conflict',
+    410:    'Gone',
+    411:    'Length Required',
+    412:    'Precondition Failed',
+    413:    'Request Entity Too Large',
+    414:    'Request URI Too Long',
+    415:    'Unsupported Media Type',
+    416:    'Requested Range Not Satisfiable',
+    417:    'Expectation Failed',
+    422:    'Unprocessable Entity',
+    423:    'Locked',
+    424:    'Failed Dependency',
+    426:    'Upgrade Required',
+    449:    'Retry With',           # propritary MS extension
+    500:    'Internal Server Error',
+    501:    'Not Implemented',
+    502:    'Bad Gateway',
+    503:    'Service Unavailable',
+    504:    'Gateway Timeout',
+    505:    'HTTP Version Not Supported',
+    507:    'Insufficient Storage',
+    510:    'Not Extended'
+}
+
+
+def _log(type, message, *args, **kwargs):
+    """Log into the internal werkzeug logger."""
+    global _logger
+    if _logger is None:
+        import logging
+        handler = logging.StreamHandler()
+        _logger = logging.getLogger('werkzeug')
+        _logger.addHandler(handler)
+        _logger.setLevel(logging.INFO)
+    getattr(_logger, type)(message.rstrip(), *args, **kwargs)
+
+
+def _parse_signature(func):
+    """Return a signature object for the function."""
+    if hasattr(func, 'im_func'):
+        func = func.im_func
+
+    # if we have a cached validator for this function, return it
+    parse = _signature_cache.get(func)
+    if parse is not None:
+        return parse
+
+    # inspect the function signature and collect all the information
+    positional, vararg_var, kwarg_var, defaults = inspect.getargspec(func)
+    defaults = defaults or ()
+    arg_count = len(positional)
+    arguments = []
+    for idx, name in enumerate(positional):
+        if isinstance(name, list):
+            raise TypeError('cannot parse functions that unpack tuples '
+                            'in the function signature')
+        try:
+            default = defaults[idx - arg_count]
+        except IndexError:
+            param = (name, False, None)
+        else:
+            param = (name, True, default)
+        arguments.append(param)
+    arguments = tuple(arguments)
+
+    def parse(args, kwargs):
+        new_args = []
+        missing = []
+        extra = {}
+
+        # consume as many arguments as positional as possible
+        for idx, (name, has_default, default) in enumerate(arguments):
+            try:
+                new_args.append(args[idx])
+            except IndexError:
+                try:
+                    new_args.append(kwargs.pop(name))
+                except KeyError:
+                    if has_default:
+                        new_args.append(default)
+                    else:
+                        missing.append(name)
+            else:
+                if name in kwargs:
+                    extra[name] = kwargs.pop(name)
+
+        # handle extra arguments
+        extra_positional = args[arg_count:]
+        if vararg_var is not None:
+            new_args.extend(extra_positional)
+            extra_positional = ()
+        if kwargs and not kwarg_var is not None:
+            extra.update(kwargs)
+            kwargs = {}
+
+        return new_args, kwargs, missing, extra, extra_positional, \
+               arguments, vararg_var, kwarg_var
+    _signature_cache[func] = parse
+    return parse
+
+
+def _patch_wrapper(old, new):
+    """Helper function that forwards all the function details to the
+    decorated function."""
+    try:
+        new.__name__ = old.__name__
+        new.__module__ = old.__module__
+        new.__doc__ = old.__doc__
+        new.__dict__ = old.__dict__
+    except:
+        pass
+    return new
+
+
+def _decode_unicode(value, charset, errors):
+    """Like the regular decode function but this one raises an
+    `HTTPUnicodeError` if errors is `strict`."""
+    fallback = None
+    if errors.startswith('fallback:'):
+        fallback = errors[9:]
+        errors = 'strict'
+    try:
+        return value.decode(charset, errors)
+    except UnicodeError, e:
+        if fallback is not None:
+            return value.decode(fallback, 'ignore')
+        from werkzeug.exceptions import HTTPUnicodeError
+        raise HTTPUnicodeError(str(e))
+
+
+def _iter_modules(path):
+    """Iterate over all modules in a package."""
+    import pkgutil
+    if hasattr(pkgutil, 'iter_modules'):
+        for importer, modname, ispkg in pkgutil.iter_modules(path):
+            yield modname, ispkg
+        return
+    from inspect import getmodulename
+    from pydoc import ispackage
+    found = set()
+    for path in path:
+        for filename in os.listdir(path):
+            p = os.path.join(path, filename)
+            modname = getmodulename(filename)
+            if modname and modname != '__init__':
+                if modname not in found:
+                    found.add(modname)
+                    yield modname, ispackage(modname)
+
+
+def _dump_date(d, delim):
+    """Used for `http_date` and `cookie_date`."""
+    if d is None:
+        d = gmtime()
+    elif isinstance(d, datetime):
+        d = d.utctimetuple()
+    elif isinstance(d, (int, long, float)):
+        d = gmtime(d)
+    return '%s, %02d%s%s%s%s %02d:%02d:%02d GMT' % (
+        ('Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun')[d.tm_wday],
+        d.tm_mday, delim,
+        ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
+         'Oct', 'Nov', 'Dec')[d.tm_mon - 1],
+        delim, str(d.tm_year), d.tm_hour, d.tm_min, d.tm_sec
+    )
+
+
+class _ExtendedMorsel(Morsel):
+    _reserved = {'httponly': 'HttpOnly'}
+    _reserved.update(Morsel._reserved)
+
+    def __init__(self, name=None, value=None):
+        Morsel.__init__(self)
+        if name is not None:
+            self.set(name, value, value)
+
+    def OutputString(self, attrs=None):
+        httponly = self.pop('httponly', False)
+        result = Morsel.OutputString(self, attrs).rstrip('\t ;')
+        if httponly:
+            result += '; HttpOnly'
+        return result
+
+
+class _StorageHelper(cgi.FieldStorage):
+    """Helper class used by `parse_form_data` to parse submitted file and
+    form data.  Don't use this class directly.  This also defines a simple
+    repr that prints just the filename as the default repr reads the
+    complete data of the stream.
+    """
+
+    FieldStorageClass = cgi.FieldStorage
+
+    def __init__(self, environ, stream_factory):
+        if stream_factory is not None:
+            self.make_file = lambda binary=None: stream_factory()
+        cgi.FieldStorage.__init__(self,
+            fp=environ['wsgi.input'],
+            environ={
+                'REQUEST_METHOD':   environ['REQUEST_METHOD'],
+                'CONTENT_TYPE':     environ['CONTENT_TYPE'],
+                'CONTENT_LENGTH':   environ['CONTENT_LENGTH']
+            },
+            keep_blank_values=True
+        )
+
+    def __repr__(self):
+        return '<%s %r>' % (
+            self.__class__.__name__,
+            self.name
+        )
+
+
+class _ExtendedCookie(BaseCookie):
+    """Form of the base cookie that doesn't raise a `CookieError` for
+    malformed keys.  This has the advantage that broken cookies submitted
+    by nonstandard browsers don't cause the cookie to be empty.
+    """
+
+    def _BaseCookie__set(self, key, real_value, coded_value):
+        morsel = self.get(key, _ExtendedMorsel())
+        try:
+            morsel.set(key, real_value, coded_value)
+        except CookieError:
+            pass
+        dict.__setitem__(self, key, morsel)
+
+
+class _DictAccessorProperty(object):
+    """Baseclass for `environ_property` and `header_property`."""
+    read_only = False
+
+    def __init__(self, name, default=None, load_func=None, dump_func=None,
+                 read_only=None, doc=None):
+        self.name = name
+        self.default = default
+        self.load_func = load_func
+        self.dump_func = dump_func
+        if read_only is not None:
+            self.read_only = read_only
+        self.__doc__ = doc
+
+    def __get__(self, obj, type=None):
+        if obj is None:
+            return self
+        storage = self.lookup(obj)
+        if self.name not in storage:
+            return self.default
+        rv = storage[self.name]
+        if self.load_func is not None:
+            try:
+                rv = self.load_func(rv)
+            except (ValueError, TypeError):
+                rv = self.default
+        return rv
+
+    def __set__(self, obj, value):
+        if self.read_only:
+            raise AttributeError('read only property')
+        if self.dump_func is not None:
+            value = self.dump_func(value)
+        self.lookup(obj)[self.name] = value
+
+    def __delete__(self, obj):
+        if self.read_only:
+            raise AttributeError('read only property')
+        self.lookup(obj).pop(self.name, None)
+
+    def __repr__(self):
+        return '<%s %s>' % (
+            self.__class__.__name__,
+            self.name
+        )
+
+
+class _UpdateDict(dict):
+    """A dict that calls `on_update` on modifications."""
+
+    def __init__(self, data, on_update):
+        dict.__init__(self, data)
+        self.on_update = on_update
+
+    def calls_update(f):
+        def oncall(self, *args, **kw):
+            rv = f(self, *args, **kw)
+            if self.on_update is not None:
+                self.on_update(self)
+            return rv
+        return _patch_wrapper(f, oncall)
+
+    __setitem__ = calls_update(dict.__setitem__)
+    __delitem__ = calls_update(dict.__delitem__)
+    clear = calls_update(dict.clear)
+    pop = calls_update(dict.pop)
+    popitem = calls_update(dict.popitem)
+    setdefault = calls_update(dict.setdefault)
+    update = calls_update(dict.update)
+
+
+
+def _easteregg(app):
+    """Like the name says."""
+    gyver = '\n'.join([x + (77 - len(x)) * ' ' for x in '''
+eJyFlzuOJDkMRP06xRjymKgDJCDQStBYT8BCgK4gTwfQ2fcFs2a2FzvZk+hvlcRvRJD148efHt9m
+9Xz94dRY5hGt1nrYcXx7us9qlcP9HHNh28rz8dZj+q4rynVFFPdlY4zH873NKCexrDM6zxxRymzz
+4QIxzK4bth1PV7+uHn6WXZ5C4ka/+prFzx3zWLMHAVZb8RRUxtFXI5DTQ2n3Hi2sNI+HK43AOWSY
+jmEzE4naFp58PdzhPMdslLVWHTGUVpSxImw+pS/D+JhzLfdS1j7PzUMxij+mc2U0I9zcbZ/HcZxc
+q1QjvvcThMYFnp93agEx392ZdLJWXbi/Ca4Oivl4h/Y1ErEqP+lrg7Xa4qnUKu5UE9UUA4xeqLJ5
+jWlPKJvR2yhRI7xFPdzPuc6adXu6ovwXwRPXXnZHxlPtkSkqWHilsOrGrvcVWXgGP3daXomCj317
+8P2UOw/NnA0OOikZyFf3zZ76eN9QXNwYdD8f8/LdBRFg0BO3bB+Pe/+G8er8tDJv83XTkj7WeMBJ
+v/rnAfdO51d6sFglfi8U7zbnr0u9tyJHhFZNXYfH8Iafv2Oa+DT6l8u9UYlajV/hcEgk1x8E8L/r
+XJXl2SK+GJCxtnyhVKv6GFCEB1OO3f9YWAIEbwcRWv/6RPpsEzOkXURMN37J0PoCSYeBnJQd9Giu
+LxYQJNlYPSo/iTQwgaihbART7Fcyem2tTSCcwNCs85MOOpJtXhXDe0E7zgZJkcxWTar/zEjdIVCk
+iXy87FW6j5aGZhttDBoAZ3vnmlkx4q4mMmCdLtnHkBXFMCReqthSGkQ+MDXLLCpXwBs0t+sIhsDI
+tjBB8MwqYQpLygZ56rRHHpw+OAVyGgaGRHWy2QfXez+ZQQTTBkmRXdV/A9LwH6XGZpEAZU8rs4pE
+1R4FQ3Uwt8RKEtRc0/CrANUoes3EzM6WYcFyskGZ6UTHJWenBDS7h163Eo2bpzqxNE9aVgEM2CqI
+GAJe9Yra4P5qKmta27VjzYdR04Vc7KHeY4vs61C0nbywFmcSXYjzBHdiEjraS7PGG2jHHTpJUMxN
+Jlxr3pUuFvlBWLJGE3GcA1/1xxLcHmlO+LAXbhrXah1tD6Ze+uqFGdZa5FM+3eHcKNaEarutAQ0A
+QMAZHV+ve6LxAwWnXbbSXEG2DmCX5ijeLCKj5lhVFBrMm+ryOttCAeFpUdZyQLAQkA06RLs56rzG
+8MID55vqr/g64Qr/wqwlE0TVxgoiZhHrbY2h1iuuyUVg1nlkpDrQ7Vm1xIkI5XRKLedN9EjzVchu
+jQhXcVkjVdgP2O99QShpdvXWoSwkp5uMwyjt3jiWCqWGSiaaPAzohjPanXVLbM3x0dNskJsaCEyz
+DTKIs+7WKJD4ZcJGfMhLFBf6hlbnNkLEePF8Cx2o2kwmYF4+MzAxa6i+6xIQkswOqGO+3x9NaZX8
+MrZRaFZpLeVTYI9F/djY6DDVVs340nZGmwrDqTCiiqD5luj3OzwpmQCiQhdRYowUYEA3i1WWGwL4
+GCtSoO4XbIPFeKGU13XPkDf5IdimLpAvi2kVDVQbzOOa4KAXMFlpi/hV8F6IDe0Y2reg3PuNKT3i
+RYhZqtkQZqSB2Qm0SGtjAw7RDwaM1roESC8HWiPxkoOy0lLTRFG39kvbLZbU9gFKFRvixDZBJmpi
+Xyq3RE5lW00EJjaqwp/v3EByMSpVZYsEIJ4APaHmVtpGSieV5CALOtNUAzTBiw81GLgC0quyzf6c
+NlWknzJeCsJ5fup2R4d8CYGN77mu5vnO1UqbfElZ9E6cR6zbHjgsr9ly18fXjZoPeDjPuzlWbFwS
+pdvPkhntFvkc13qb9094LL5NrA3NIq3r9eNnop9DizWOqCEbyRBFJTHn6Tt3CG1o8a4HevYh0XiJ
+sR0AVVHuGuMOIfbuQ/OKBkGRC6NJ4u7sbPX8bG/n5sNIOQ6/Y/BX3IwRlTSabtZpYLB85lYtkkgm
+p1qXK3Du2mnr5INXmT/78KI12n11EFBkJHHp0wJyLe9MvPNUGYsf+170maayRoy2lURGHAIapSpQ
+krEDuNoJCHNlZYhKpvw4mspVWxqo415n8cD62N9+EfHrAvqQnINStetek7RY2Urv8nxsnGaZfRr/
+nhXbJ6m/yl1LzYqscDZA9QHLNbdaSTTr+kFg3bC0iYbX/eQy0Bv3h4B50/SGYzKAXkCeOLI3bcAt
+mj2Z/FM1vQWgDynsRwNvrWnJHlespkrp8+vO1jNaibm+PhqXPPv30YwDZ6jApe3wUjFQobghvW9p
+7f2zLkGNv8b191cD/3vs9Q833z8t'''.decode('base64').decode('zlib').splitlines()])
+    def easteregged(environ, start_response):
+        def injecting_start_response(status, headers, exc_info=None):
+            headers.append(('X-Powered-By', 'Werkzeug'))
+            return start_response(status, headers, exc_info)
+        if environ.get('QUERY_STRING') != 'macgybarchakku':
+            return app(environ, injecting_start_response)
+        injecting_start_response('200 OK', [('Content-Type', 'text/html')])
+        return ['''<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<title>About Werkzeug</>
+<style type="text/css">
+  body { font: 15px Georgia, serif; text-align: center; }
+  a { color: #333; text-decoration: none; }
+  h1 { font-size: 30px; margin: 20px 0 10px 0; }
+  p { margin: 0 0 30px 0; }
+  pre { font: 11px 'Consolas', 'Monaco', monospace; line-height: 0.95; }
+</style>
+<h1><a href="http://werkzeug.pocoo.org/">Werkzeug</a></h1>
+<p>the Swiss Army knife of Python web development.
+<pre>%s\n\n\n</>''' % gyver]
+    return easteregged
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/contrib/__init__.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+"""
+    `werkzeug.contrib`
+    ~~~~~~~~~~~~~~~~~~
+
+    Contains user-submitted code that other users may find useful,
+    but which are not part of Werkzeug core. Anyone can write
+    code for inclusion in the `contrib` package.  All the modules
+    in this package are distributed as an addon library and thus not
+    part of `werkzeug` itself.
+
+    This file itself is mostly for informational purposes and to
+    tell the Python interpreter that `contrib` is a package.
+
+
+    :copyright: 2007-2008 by Marek Kubica, Marian Sigler, Armin Ronacher,
+                Leif K-Brooks, Ronny Pfannschmid, Thomas Johansson.
+    :license: BSD, see LICENSE for more details.
+"""
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/contrib/atom.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,351 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.contrib.atom
+    ~~~~~~~~~~~~~~~~~~~~~
+
+    This module provides a class called `AtomFeed` which can be used
+    to generate Atom feeds.
+
+    :copyright: Copyright 2007 by Armin Ronacher, Marian Sigler.
+    :license: GNU GPL.
+"""
+from datetime import datetime
+from werkzeug.utils import escape
+from werkzeug.wrappers import BaseResponse
+
+
+XHTML_NAMESPACE = 'http://www.w3.org/1999/xhtml'
+
+
+def _make_text_block(name, content, content_type=None):
+    """Helper function for the builder that creates an XML text block."""
+    if content_type == 'xhtml':
+        return u'<%s type="xhtml"><div xmlns="%s">%s</div></%s>\n' % \
+               (name, XHTML_NAMESPACE, content, name)
+    if not content_type:
+        return u'<%s>%s</%s>\n' % (name, escape(content), name)
+    return u'<%s type="%s">%s</%s>\n' % (name, content_type,
+                                         escape(content), name)
+
+
+def format_iso8601(obj):
+    """Format a datetime object for iso8601"""
+    return obj.strftime('%Y-%m-%dT%H:%M:%SZ')
+
+
+class AtomFeed(object):
+    """A helper class that creates Atom feeds."""
+    default_generator = ('Werkzeug', None, None)
+
+    def __init__(self, title=None, entries=None, **kwargs):
+        """Create an Atom feed.
+
+        :Parameters:
+          title
+            the title of the feed. Required.
+          title_type
+            the type attribute for the title element. One of html, text,
+            xhtml. Default is text.
+          url
+            the url for the feed (not the url *of* the feed)
+          id
+            a globally unique id for the feed. Must be an URI. If not present
+            the `feed_url` is used, but one of both is required.
+          updated
+            the time the feed was modified the last time. Must be a `datetime`
+            object. If not present the latest entry's `updated` is used.
+          feed_url
+            the url to the feed. Should be the URL that was requested.
+          author
+            the author of the feed. Must be either a string (the name) or a
+            dict with name (required) and uri or email (both optional). Can be
+            a list of (may be mixed, too) strings and dicts, too, if there are
+            multiple authors. Required if not every entry has an author
+            element.
+          icon
+            an icon for the feed.
+          logo
+            a logo for the feed.
+          rights
+            copyright information for the feed.
+          rights_type
+            the type attribute for the rights element. One of html, text,
+            xhtml. Default is text.
+          subtitle
+            a short description of the feed.
+          subtitle_type
+            the type attribute for the subtitle element. One of html, text,
+            xhtml. Default is text.
+          links
+            additional links. Must be a list of dictionaries with href
+            (required) and rel, type, hreflang, title, length (all optional)
+          generator
+            the software that generated this feed.  This must be a tuple in
+            the form ``(name, url, version)``.  If you don't want to specify
+            one of them, set the item to None.
+          entries
+            a list with the entries for the feed. Entries can also be added
+            later with add().
+
+        For more information on the elements see
+        http://www.atomenabled.org/developers/syndication/
+
+        Everywhere where a list is demanded, any iterable can be used.
+        """
+        self.title = title
+        self.title_type = kwargs.get('title_type', 'text')
+        self.url = kwargs.get('url')
+        self.feed_url = kwargs.get('feed_url', self.url)
+        self.id = kwargs.get('id', self.feed_url)
+        self.updated = kwargs.get('updated')
+        self.author = kwargs.get('author', ())
+        self.icon = kwargs.get('icon')
+        self.logo = kwargs.get('logo')
+        self.rights = kwargs.get('rights')
+        self.rights_type = kwargs.get('rights_type')
+        self.subtitle = kwargs.get('subtitle')
+        self.subtitle_type = kwargs.get('subtitle_type', 'text')
+        self.generator = kwargs.get('generator')
+        if self.generator is None:
+            self.generator = self.default_generator
+        self.links = kwargs.get('links', [])
+        self.entries = entries and list(entries) or []
+
+        if not hasattr(self.author, '__iter__') \
+           or isinstance(self.author, (basestring, dict)):
+            self.author = [self.author]
+        for i, author in enumerate(self.author):
+            if not isinstance(author, dict):
+                self.author[i] = {'name': author}
+
+        if not self.title:
+            raise ValueError('title is required')
+        if not self.id:
+            raise ValueError('id is required')
+        for author in self.author:
+            if 'name' not in author:
+                raise TypeError('author must contain at least a name')
+
+    def add(self, *args, **kwargs):
+        """add a new entry to the feed"""
+        if len(args) == 1 and not kwargs and isinstance(args[0], FeedEntry):
+            self.entries.append(args[0])
+        else:
+            kwargs['feed_url'] = self.feed_url
+            self.entries.append(FeedEntry(*args, **kwargs))
+
+    def __repr__(self):
+        return '<%s %r (%d entries)>' % (
+            self.__class__.__name__,
+            self.title,
+            len(self.entries)
+        )
+
+    def generate(self):
+        """Return a generator that yields pieces of XML."""
+        # atom demands either an author element in every entry or a global one
+        if not self.author:
+            if False in map(lambda e: bool(e.author), self.entries):
+                self.author = ({'name': u'unbekannter Autor'},)
+
+        if not self.updated:
+            dates = sorted([entry.updated for entry in self.entries])
+            self.updated = dates and dates[-1] or datetime.utcnow()
+
+        yield u'<?xml version="1.0" encoding="utf-8"?>\n'
+        yield u'<feed xmlns="http://www.w3.org/2005/Atom">\n'
+        yield '  ' + _make_text_block('title', self.title, self.title_type)
+        yield u'  <id>%s</id>\n' % escape(self.id)
+        yield u'  <updated>%s</updated>\n' % format_iso8601(self.updated)
+        if self.url:
+            yield u'  <link href="%s" />\n' % escape(self.url, True)
+        if self.feed_url:
+            yield u'  <link href="%s" rel="self" />\n' % \
+                escape(self.feed_url, True)
+        for link in self.links:
+            yield u'  <link %s/>\n' % ''.join('%s="%s" ' % \
+                [(k, escape(link[k], True)) for k in link])
+        for author in self.author:
+            yield u'  <author>\n'
+            yield u'    <name>%s</name>\n' % escape(author['name'])
+            if 'uri' in author:
+                yield u'    <uri>%s</uri>\n' % escape(author['uri'])
+            if 'email' in author:
+                yield '    <email>%s</email>\n' % escape(author['email'])
+            yield '  </author>\n'
+        if self.subtitle:
+            yield '  ' + _make_text_block('subtitle', self.subtitle,
+                                          self.subtitle_type)
+        if self.icon:
+            yield u'  <icon>%s</icon>\n' % escape(self.icon)
+        if self.logo:
+            yield u'  <logo>%s</logo>\n' % escape(self.logo)
+        if self.rights:
+            yield '  ' + _make_text_block('rights', self.rights,
+                                          self.rights_type)
+        generator_name, generator_url, generator_version = self.generator
+        if generator_name or generator_url or generator_version:
+            tmp = [u'  <generator']
+            if generator_url:
+                tmp.append(u' uri="%s"' % escape(generator_url, True))
+            if generator_version:
+                tmp.append(u' version="%s"' % escape(generator_version, True))
+            tmp.append(u'>%s</generator>\n' % escape(generator_name))
+            yield u''.join(tmp)
+        for entry in self.entries:
+            for line in entry.generate():
+                yield u'  ' + line
+        yield u'</feed>\n'
+
+    def to_string(self):
+        """Convert the feed into a string."""
+        return u''.join(self.generate())
+
+    def get_response(self):
+        """Return a response object for the feed."""
+        return BaseResponse(self.to_string(), mimetype='application/atom+xml')
+
+    def __call__(self, environ, start_response):
+        """Use the class as WSGI response object."""
+        return self.get_response(environ, start_response)
+
+    def __unicode__(self):
+        return self.to_string()
+
+    def __str__(self):
+        return self.to_string().encode('utf-8')
+
+
+class FeedEntry(object):
+    """Represents a single entry in a feed."""
+
+    def __init__(self, title=None, content=None, feed_url=None, **kwargs):
+        """Holds an Atom feed entry.
+
+        :Parameters:
+          title
+            the title of the entry. Required.
+          title_type
+            the type attribute for the title element. One of html, text,
+            xhtml. Default is text.
+          content
+            the content of the entry.
+          content_type
+            the type attribute for the content element. One of html, text,
+            xhtml. Default is text.
+          summary
+            a summary of the entry's content.
+          summary_type
+            a type attribute for the summary element. One of html, text,
+            xhtml. Default is text.
+          url
+            the url for the entry.
+          id
+            a globally unique id for the entry. Must be an URI. If not present
+            the URL is used, but one of both is required.
+          updated
+            the time the entry was modified the last time. Must be a
+            `datetime` object. Required.
+          author
+            the author of the entry. Must be either a string (the name) or a
+            dict with name (required) and uri or email (both optional). Can
+            be a list of (may be mixed, too) strings and dicts, too, if there
+            are multiple authors. Required if there is no author for the
+            feed.
+          published
+            the time the entry was initially published. Must be a `datetime`
+            object.
+          rights
+            copyright information for the entry.
+          rights_type
+            the type attribute for the rights element. One of html, text,
+            xhtml. Default is text.
+          links
+            additional links. Must be a list of dictionaries with href
+            (required) and rel, type, hreflang, title, length (all optional)
+          xml_base
+            The xml base (url) for this feed item.  If not provided it will
+            default to the item url.
+
+        For more information on the elements see
+        http://www.atomenabled.org/developers/syndication/
+
+        Everywhere where a list is demanded, any iterable can be used.
+        """
+        self.title = title
+        self.title_type = kwargs.get('title_type', 'text')
+        self.content = content
+        self.content_type = kwargs.get('content_type', 'html')
+        self.url = kwargs.get('url')
+        self.id = kwargs.get('id', self.url)
+        self.updated = kwargs.get('updated')
+        self.summary = kwargs.get('summary')
+        self.summary_type = kwargs.get('summary_type', 'html')
+        self.author = kwargs.get('author')
+        self.published = kwargs.get('published')
+        self.rights = kwargs.get('rights')
+        self.links = kwargs.get('links', [])
+        self.xml_base = kwargs.get('xml_base', feed_url)
+
+        if not hasattr(self.author, '__iter__') \
+           or isinstance(self.author, (basestring, dict)):
+            self.author = [self.author]
+        for i, author in enumerate(self.author):
+            if not isinstance(author, dict):
+                self.author[i] = {'name': author}
+
+        if not self.title:
+            raise ValueError('title is required')
+        if not self.id:
+            raise ValueError('id is required')
+        if not self.updated:
+            raise ValueError('updated is required')
+
+    def __repr__(self):
+        return '<%s %r>' % (
+            self.__class__.__name__,
+            self.title
+        )
+
+    def generate(self):
+        """Yields pieces of ATOM XML."""
+        base = ''
+        if self.xml_base:
+            base = ' xml:base="%s"' % escape(self.xml_base, True)
+        yield u'<entry%s>\n' % base
+        yield u'  ' + _make_text_block('title', self.title, self.title_type)
+        yield u'  <id>%s</id>\n' % escape(self.id)
+        yield u'  <updated>%s</updated>\n' % format_iso8601(self.updated)
+        if self.published:
+            yield u'  <published>%s</published>\n' % \
+                  format_iso8601(self.published)
+        if self.url:
+            yield u'  <link href="%s" />\n' % escape(self.url)
+        for author in self.author:
+            yield u'  <author>\n'
+            yield u'    <name>%s</name>\n' % escape(author['name'])
+            if 'uri' in author:
+                yield u'    <uri>%s</uri>\n' % escape(author['uri'])
+            if 'email' in author:
+                yield u'    <email>%s</email>\n' % escape(author['email'])
+            yield u'  </author>\n'
+        for link in self.links:
+            yield u'  <link %s/>\n' % ''.join('%s="%s" ' % \
+                [(k, escape(link[k], True)) for k in link])
+        if self.summary:
+            yield u'  ' + _make_text_block('summary', self.summary,
+                                           self.summary_type)
+        if self.content:
+            yield u'  ' + _make_text_block('content', self.content,
+                                           self.content_type)
+        yield u'</entry>\n'
+
+    def to_string(self):
+        """Convert the feed item into a unicode object."""
+        return u''.join(self.generate())
+
+    def __unicode__(self):
+        return self.to_string()
+
+    def __str__(self):
+        return self.to_string().encode('utf-8')
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/contrib/cache.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,310 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.contrib.cache
+    ~~~~~~~~~~~~~~~~~~~~~~
+
+    Small helper module that provides a simple interface to memcached, a
+    simple django-inspired in-process cache and a file system based cache.
+
+    The idea is that it's possible to switch caching systems without changing
+    much code in the application.
+
+
+    :copyright: 2007-2008 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+import os
+import re
+try:
+    from hashlib import md5
+except ImportError:
+    from md5 import new as md5
+from itertools import izip
+from time import time
+from cPickle import loads, dumps, load, dump, HIGHEST_PROTOCOL
+
+have_memcache = True
+try:
+    import cmemcache as memcache
+    is_cmemcache = True
+except ImportError:
+    try:
+        import memcache
+        is_cmemcache = False
+    except ImportError:
+        have_memcache = False
+
+
+class BaseCache(object):
+    """Baseclass for the cache systems."""
+
+    def __init__(self, default_timeout=300):
+        self.default_timeout = default_timeout
+
+    def get(self, key):
+        return None
+    delete = get
+
+    def get_many(self, *keys):
+        return map(self.get, keys)
+
+    def get_dict(self, *keys):
+        return dict(izip(keys, self.get_many(keys)))
+
+    def set(self, key, value, timeout=None):
+        pass
+    add = set
+
+    def set_many(self, mapping, timeout=None):
+        for key, value in mapping.iteritems():
+            self.set(key, value, timeout)
+
+    def delete_many(self, *keys):
+        for key in keys:
+            self.delete(key)
+
+    def clear(self):
+        pass
+
+    def inc(self, key, delta=1):
+        self.set(key, (self.get(key) or 0) + delta)
+
+    def dec(self, key, delta=1):
+        self.set(key, (self.get(key) or 0) - delta)
+
+
+class NullCache(BaseCache):
+    """A cache that doesn't cache."""
+
+
+class SimpleCache(BaseCache):
+    """Simple memory cache for single process environments.  This class exists
+    mainly for the development server and is not 100% thread safe.  It tries
+    to use as many atomic operations as possible and no locks for simplicity
+    but it could happen under heavy load that keys are added multiple times.
+    """
+
+    def __init__(self, threshold=500, default_timeout=300):
+        BaseCache.__init__(self, default_timeout)
+        self._cache = {}
+        self.clear = self._cache.clear
+        self._threshold = threshold
+
+    def _prune(self):
+        if len(self._cache) > self._threshold:
+            now = time()
+            for idx, (key, (expires, _)) in enumerate(self._cache.items()):
+                if expires <= now or idx % 3 == 0:
+                    self._cache.pop(key, None)
+
+    def get(self, key):
+        now = time()
+        expires, value = self._cache.get(key, (0, None))
+        if expires > time():
+            return loads(value)
+
+    def set(self, key, value, timeout=None):
+        if timeout is None:
+            timeout = self.default_timeout
+        self._prune()
+        self._cache[key] = (time() + timeout, dumps(value, HIGHEST_PROTOCOL))
+
+    def add(self, key, value, timeout=None):
+        if timeout is None:
+            timeout = self.default_timeout
+        if len(self._cache) > self._threshold:
+            self._prune()
+        item = (time() + timeout, dumps(value, HIGHEST_PROTOCOL))
+        self._cache.setdefault(key, item)
+
+    def delete(self, key):
+        self._cache.pop(key, None)
+
+
+_test_memcached_key = re.compile(r'[^\x00-\x21\xff]{1,250}$').match
+
+class MemcachedCache(BaseCache):
+    """A cache that uses memcached as backend.
+
+    Implementation notes:  This cache backend works around some limitations in
+    memcached to simplify the interface.  For example unicode keys are encoded
+    to utf-8 on the fly.  Methods such as `get_dict` return the keys in the
+    same format as passed.  Furthermore all get methods silently ignore key
+    errors to not cause problems when untrusted user data is passed to the get
+    methods which is often the case in web applications.
+    """
+
+    def __init__(self, servers, default_timeout=300):
+        BaseCache.__init__(self, default_timeout)
+        if not have_memcache:
+            raise RuntimeError('no memcache module found')
+
+        # cmemcache has a bug that debuglog is not defined for the
+        # client.  Whenever pickle fails you get a weird AttributError.
+        if is_cmemcache:
+            self._client = memcache.Client(map(str, servers))
+            try:
+                self._client.debuglog = lambda *a: None
+            except:
+                pass
+        else:
+            self._client = memcache.Client(servers, False, HIGHEST_PROTOCOL)
+
+    def get(self, key):
+        if isinstance(key, unicode):
+            key = key.encode('utf-8')
+        # memcached doesn't support keys longer than that.  Because often
+        # checks for so long keys can occour because it's tested from user
+        # submitted data etc we fail silently for getting.
+        if _test_memcached_key(key):
+            return self._client.get(key)
+
+    def get_dict(self, *keys):
+        key_mapping = {}
+        have_encoded_keys = False
+        for idx, key in enumerate(keys):
+            if isinstance(key, unicode):
+                encoded_key = key.encode('utf-8')
+                have_encoded_keys = True
+            else:
+                encoded_key = key
+            if _test_memcached_key(key):
+                key_mapping[encoded_key] = key
+        # the keys call here is important because otherwise cmemcache
+        # does ugly things.  What exaclty I don't know, i think it does
+        # Py_DECREF but quite frankly i don't care.
+        d = rv = self._client.get_multi(key_mapping.keys())
+        if have_encoded_keys:
+            rv = {}
+            for key, value in d.iteritems():
+                rv[key_mapping[key]] = value
+        if len(rv) < len(keys):
+            for key in keys:
+                if key not in rv:
+                    rv[key] = None
+        return rv
+
+    def add(self, key, value, timeout=None):
+        if timeout is None:
+            timeout = self.default_timeout
+        if isinstance(key, unicode):
+            key = key.encode('utf-8')
+        self._client.add(key, value, timeout)
+
+    def set(self, key, value, timeout=None):
+        if timeout is None:
+            timeout = self.default_timeout
+        if isinstance(key, unicode):
+            key = key.encode('utf-8')
+        self._client.set(key, value, timeout)
+
+    def get_many(self, *keys):
+        d = self.get_dict(*keys)
+        return [d[key] for key in keys]
+
+    def set_many(self, mapping, timeout=None):
+        if timeout is None:
+            timeout = self.default_timeout
+        new_mapping = {}
+        for key, value in mapping.iteritems():
+            if isinstance(key, unicode):
+                key = key.encode('utf-8')
+            new_mapping[key] = value
+        self._client.set_multi(new_mapping, timeout)
+
+    def delete(self, key):
+        if isinstance(key, unicode):
+            key = key.encode('utf-8')
+        self._client.delete(key)
+
+    def delete_many(self, *keys):
+        keys = list(keys)
+        for idx, key in enumerate(keys):
+            if isinstance(key, unicode):
+                keys[idx] = key.encode('utf-8')
+        self._client.delete_multi(keys)
+
+    def clear(self):
+        self._client.flush_all()
+
+    def inc(self, key, delta=1):
+        if isinstance(key, unicode):
+            key = key.encode('utf-8')
+        self._client.incr(key, key, delta)
+
+    def dec(self, key, delta=1):
+        if isinstance(key, unicode):
+            key = key.encode('utf-8')
+        self._client.decr(key, key, delta)
+
+
+class FileSystemCache(BaseCache):
+    """A cache that stores the items on the file system."""
+
+    def __init__(self, cache_dir, threshold=500, default_timeout=300):
+        BaseCache.__init__(self, default_timeout)
+        self._path = cache_dir
+        self._threshold = threshold
+        if not os.path.exists(self._path):
+            os.makedirs(self._path)
+
+    def _prune(self):
+        entries = os.listdir(self._path)
+        if len(entries) > self._threshold:
+            now = time()
+            for idx, key in enumerate(entries):
+                try:
+                    f = file(self._get_filename(key))
+                    if pickle.load(f) > now and idx % 3 != 0:
+                        f.close()
+                        continue
+                except:
+                    f.close()
+                self.delete(key)
+
+    def _get_filename(self, key):
+        hash = md5(key).hexdigest()
+        return os.path.join(self._path, hash)
+
+    def get(self, key):
+        filename = self._get_filename(key)
+        try:
+            f = file(filename, 'rb')
+            try:
+                if load(f) >= time():
+                    return load(f)
+            finally:
+                f.close()
+            os.remove(filename)
+        except:
+            return None
+
+    def add(self, key, value, timeout=None):
+        filename = self._get_filename(key)
+        if not os.path.exists(filename):
+            self.set(key, value, timeout)
+
+    def set(self, key, value, timeout=None):
+        if timeout is None:
+            timeout = self.default_timeout
+        filename = self._get_filename(key)
+        self._prune()
+        try:
+            f = file(filename, 'wb')
+            try:
+                dump(int(time() + timeout), f, 1)
+                dump(value, f, HIGHEST_PROTOCOL)
+            finally:
+                f.close()
+        except (IOError, OSError):
+            pass
+
+    def delete(self, key):
+        try:
+            os.remove(self._get_filename(key))
+        except (IOError, OSError):
+            pass
+
+    def clear(self):
+        for key in os.listdir(self._path):
+            self.delete(key)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/contrib/iterio.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,278 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.contrib.iterio
+    ~~~~~~~~~~~~~~~~~~~~~~~
+
+    This module implements a `IterIO` that converts an iterator into a stream
+    object and the other way round.  Converting streams into iterators
+    requires the `greenlet`_ module.
+
+
+    To convert an iterator into a stream all you have to do is to pass it
+    directly to the `IterIO` constructor.  In this example we pass it a newly
+    created generator::
+
+        def foo():
+            yield "something\n"
+            yield "otherthings"
+        stream = IterIO(foo())
+        print stream.read()         # read the whole iterator
+
+    The other way round works a bit different because we have to ensure that
+    the code execution doesn't take place yet.  An `IterIO` call with a
+    callable as first argument does two things.  The function itself is passed
+    an `IterI` stream it can feed.  The object returned by the `IterIO`
+    constructor on the other hand is not an stream object but an iterator::
+
+        def foo(stream):
+            stream.write("some")
+            stream.write("thing")
+            stream.flush()
+            stream.write("otherthing")
+        iterator = IterIO(foo)
+        print iterator.next()       # prints something
+        print iterator.next()       # prints otherthing
+        iterator.next()             # raises StopIteration
+
+
+    .. _greenlet: http://codespeak.net/py/dist/greenlet.html
+
+    :copyright: 2007 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+try:
+    from py.magic import greenlet
+except (RuntimeError, ImportError):
+    greenlet = None
+
+
+class IterIO(object):
+    """
+    Baseclass for iterator IOs.
+    """
+
+    def __new__(cls, obj):
+        try:
+            iterator = iter(obj)
+        except TypeError:
+            return IterI(obj)
+        return IterO(iterator)
+
+    def __iter__(self):
+        return self
+
+    def tell(self):
+        if self.closed:
+            raise ValueError('I/O operation on closed file')
+        return self.pos
+
+    def isatty(self):
+        if self.closed:
+            raise ValueError('I/O operation on closed file')
+        return False
+
+    def seek(self, pos, mode=0):
+        if self.closed:
+            raise ValueError('I/O operation on closed file')
+        raise IOError(9, 'Bad file descriptor')
+
+    def truncate(self, size=None):
+        if self.closed:
+            raise ValueError('I/O operation on closed file')
+        raise IOError(9, 'Bad file descriptor')
+
+    def write(self, s):
+        if self.closed:
+            raise ValueError('I/O operation on closed file')
+        raise IOError(9, 'Bad file descriptor')
+
+    def writelines(self, list):
+        if self.closed:
+            raise ValueError('I/O operation on closed file')
+        raise IOError(9, 'Bad file descriptor')
+
+    def read(self, n=-1):
+        if self.closed:
+            raise ValueError('I/O operation on closed file')
+        raise IOError(9, 'Bad file descriptor')
+
+    def readlines(self, sizehint=0):
+        if self.closed:
+            raise ValueError('I/O operation on closed file')
+        raise IOError(9, 'Bad file descriptor')
+
+    def readline(self, length=None):
+        if self.closed:
+            raise ValueError('I/O operation on closed file')
+        raise IOError(9, 'Bad file descriptor')
+
+    def flush(self):
+        if self.closed:
+            raise ValueError('I/O operation on closed file')
+        raise IOError(9, 'Bad file descriptor')
+
+    def next(self):
+        if self.closed:
+            raise StopIteration()
+        line = self.readline()
+        if not line:
+            raise StopIteration()
+        return line
+
+
+class IterI(IterIO):
+    """
+    Convert an stream into an iterator.
+    """
+
+    def __new__(cls, func):
+        if greenlet is None:
+            raise RuntimeError('IterI requires greenlet support')
+        stream = object.__new__(cls)
+        stream.__init__(greenlet.getcurrent())
+
+        def run():
+            func(stream)
+            stream.flush()
+
+        g = greenlet(run, stream._parent)
+        while 1:
+            rv = g.switch()
+            if not rv:
+                return
+            yield rv[0]
+
+    def __init__(self, parent):
+        self._parent = parent
+        self._buffer = []
+        self.closed = False
+        self.pos = 0
+
+    def close(self):
+        if not self.closed:
+            self.closed = True
+
+    def write(self, s):
+        if self.closed:
+            raise ValueError('I/O operation on closed file')
+        self.pos += len(s)
+        self._buffer.append(s)
+
+    def writelines(slf, list):
+        self.write(''.join(list))
+
+    def flush(self):
+        if self.closed:
+            raise ValueError('I/O operation on closed file')
+        data = ''.join(self._buffer)
+        self._buffer = []
+        self._parent.switch((data,))
+
+
+class IterO(IterIO):
+    """
+    Iter output.  Wrap an iterator and give it a stream like interface.
+    """
+
+    __new__ = object.__new__
+
+    def __init__(self, gen):
+        self._gen = gen
+        self._buf = ''
+        self.closed = False
+        self.pos = 0
+
+    def __iter__(self):
+        return self
+
+    def close(self):
+        if not self.closed:
+            self.closed = True
+            if hasattr(self._gen, 'close'):
+                self._gen.close()
+
+    def seek(self, pos, mode=0):
+        if self.closed:
+            raise ValueError('I/O operation on closed file')
+        if mode == 1:
+            pos += self.pos
+        elif mode == 2:
+            pos += len(self._buf)
+        try:
+            buf = []
+            tmp_end_pos = len(self._buf)
+            while pos > tmp_end_pos:
+                item = self._gen.next()
+                tmp_end_pos += len(item)
+                buf.append(item)
+            if buf:
+                self._buf += ''.join(buf)
+        except StopIteration:
+            pass
+        self.pos = max(0, pos)
+
+    def read(self, n=-1):
+        if self.closed:
+            raise ValueError('I/O operation on closed file')
+        if n < 0:
+            self._buf += ''.join(self._gen)
+            return self._buf[self.pos:]
+        new_pos = self.pos + n
+        try:
+            buf = []
+            tmp_end_pos = len(self._buf)
+            while new_pos > tmp_end_pos:
+                item = self._gen.next()
+                tmp_end_pos += len(item)
+                buf.append(item)
+            if buf:
+                self._buf += ''.join(buf)
+        except StopIteration:
+            pass
+        new_pos = max(0, new_pos)
+        try:
+            return self._buf[self.pos:new_pos]
+        finally:
+            self.pos = new_pos
+
+    def readline(self, length=None):
+        if self.closed:
+            raise ValueError('I/O operation on closed file')
+        nl_pos = self._buf.find('\n', self.pos)
+        buf = []
+        try:
+            pos = self.pos
+            while nl_pos < 0:
+                item = self._gen.next()
+                pos2 = item.find('\n', pos)
+                buf.append(item)
+                if pos2 >= 0:
+                    nl_pos = pos
+                    break
+                pos += len(item)
+        except StopIteration:
+            pass
+        if buf:
+            self._buf += ''.join(buf)
+        if nl_pos < 0:
+            new_pos = len(self._buf)
+        else:
+            new_pos = nl_pos + 1
+        if length is not None and self.pos + length < new_pos:
+            new_pos = self.pos + length
+        try:
+            return self._buf[self.pos:new_pos]
+        finally:
+            self.pos = new_pos
+
+    def readlines(self, sizehint=0):
+        total = 0
+        lines = []
+        line = self.readline()
+        while line:
+            lines.append(line)
+            total += len(line)
+            if 0 < sizehint <= total:
+                break
+            line = self.readline()
+        return lines
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/contrib/jsrouting.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,258 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.contrib.jsrouting
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Addon module that allows to create a JavaScript function from a map
+    that generates rules.
+
+    :copyright: 2007 by Armin Ronacher, Leif K-Brooks.
+    :license: BSD, see LICENSE for more details.
+"""
+try:
+    from simplejson import dumps
+except ImportError:
+    def dumps(*args):
+        raise RuntimeErrr('simplejson required for jsrouting')
+
+from inspect import getmro
+from werkzeug.minitmpl import Template
+from werkzeug.routing import NumberConverter
+
+
+_javascript_routing_template = Template(u'''\
+<% if name_parts %>\
+<% for idx in xrange(0, len(name_parts) - 1) %>\
+if (typeof ${'.'.join(name_parts[:idx + 1])} === 'undefined') \
+${'.'.join(name_parts[:idx + 1])} = {};
+<% endfor %>\
+${'.'.join(name_parts)} = <% endif %>\
+(function (server_name, script_name, subdomain, url_scheme) {
+    var converters = ${', '.join(converters)};
+    var rules = $rules;
+    function in_array(array, value) {
+        if (array.indexOf != undefined) {
+            return array.indexOf(value) != -1;
+        }
+        for (var i = 0; i < array.length; i++) {
+            if (array[i] == value) {
+                return true;
+            }
+        }
+        return false;
+    }
+    function array_diff(array1, array2) {
+        array1 = array1.slice();
+        for (var i = array1.length-1; i >= 0; i--) {
+            if (in_array(array2, array1[i])) {
+                array1.splice(i, 1);
+            }
+        }
+        return array1;
+    }
+    function split_obj(obj) {
+        var names = [];
+        var values = [];
+        for (var name in obj) {
+            if (typeof(obj[name]) != 'function') {
+                names.push(name);
+                values.push(obj[name]);
+            }
+        }
+        return {names: names, values: values, original: obj};
+    }
+    function suitable(rule, args) {
+        var default_args = split_obj(rule.defaults || {});
+        var diff_arg_names = array_diff(rule.arguments, default_args.names);
+
+        for (var i = 0; i < diff_arg_names.length; i++) {
+            if (!in_array(args.names, diff_arg_names[i])) {
+                return false;
+            }
+        }
+
+        if (array_diff(rule.arguments, args.names).length == 0) {
+            if (rule.defaults == null) {
+                return true;
+            }
+            for (var i = 0; i < default_args.names.length; i++) {
+                var key = default_args.names[i];
+                var value = default_args.values[i];
+                if (value != args.original[key]) {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
+    function build(rule, args) {
+        var tmp = [];
+        var processed = rule.arguments.slice();
+        for (var i = 0; i < rule.trace.length; i++) {
+            var part = rule.trace[i];
+            if (part.is_dynamic) {
+                var converter = converters[rule.converters[part.data]];
+                var data = converter(args.original[part.data]);
+                if (data == null) {
+                    return null;
+                }
+                tmp.push(data);
+                processed.push(part.name);
+            } else {
+                tmp.push(part.data);
+            }
+        }
+        tmp = tmp.join('');
+        var pipe = tmp.indexOf('|');
+        var subdomain = tmp.substring(0, pipe);
+        var url = tmp.substring(pipe+1);
+
+        var unprocessed = array_diff(args.names, processed);
+        var first_query_var = true;
+        for (var i = 0; i < unprocessed.length; i++) {
+            if (first_query_var) {
+                url += '?';
+            } else {
+                url += '&';
+            }
+            first_query_var = false;
+            url += encodeURIComponent(unprocessed[i]);
+            url += '=';
+            url += encodeURIComponent(args.original[unprocessed[i]]);
+        }
+        return {subdomain: subdomain, path: url};
+    }
+    function lstrip(s, c) {
+        while (s && s.substring(0, 1) == c) {
+            s = s.substring(1);
+        }
+        return s;
+    }
+    function rstrip(s, c) {
+        while (s && s.substring(s.length-1, s.length) == c) {
+            s = s.substring(0, s.length-1);
+        }
+        return s;
+    }
+    return function(endpoint, args, force_external) {
+        args = split_obj(args);
+        var rv = null;
+        for (var i = 0; i < rules.length; i++) {
+            var rule = rules[i];
+            if (rule.endpoint != endpoint) continue;
+            if (suitable(rule, args)) {
+                rv = build(rule, args);
+                if (rv != null) {
+                    break;
+                }
+            }
+        }
+        if (rv == null) {
+            return null;
+        }
+        if (!force_external && rv.subdomain == subdomain) {
+            return rstrip(script_name, '/') + '/' + lstrip(rv.path, '/');
+        } else {
+            return url_scheme + '://'
+                   + (rv.subdomain ? rv.subdomain + '.' : '')
+                   + server_name + rstrip(script_name, '/')
+                   + '/' + lstrip(rv.path, '/');
+        }
+    };
+})''')
+
+
+def generate_map(map, name='url_map'):
+    """
+    Generates a JavaScript function containing the rules defined in
+    this map, to be used with a MapAdapter's generate_javascript
+    method.  If you don't pass a name the returned JavaScript code is
+    an expression that returns a function.  Otherwise it's a standalone
+    script that assigns the function with that name.  Dotted names are
+    resolved (so you an use a name like 'obj.url_for')
+
+    In order to use JavaScript generation, simplejson must be installed.
+
+    Note that using this feature will expose the rules
+    defined in your map to users. If your rules contain sensitive
+    information, don't use JavaScript generation!
+    """
+    map.update()
+    rules = []
+    converters = []
+    for rule in map.iter_rules():
+        trace = [{
+            'is_dynamic':   is_dynamic,
+            'data':         data
+        } for is_dynamic, data in rule._trace]
+        rule_converters = {}
+        for key, converter in rule._converters.iteritems():
+            js_func = js_to_url_function(converter)
+            try:
+                index = converters.index(js_func)
+            except ValueError:
+                converters.append(js_func)
+                index = len(converters) - 1
+            rule_converters[key] = index
+        rules.append({
+            u'endpoint':    rule.endpoint,
+            u'arguments':   list(rule.arguments),
+            u'converters':  rule_converters,
+            u'trace':       trace,
+            u'defaults':    rule.defaults
+        })
+
+    return _javascript_routing_template.render({
+        'name_parts':   name and name.split('.') or [],
+        'rules':        dumps(rules),
+        'converters':   converters
+    })
+
+
+def generate_adapter(adapter, name='url_for', map_name='url_map'):
+    """Generates the url building function for a map."""
+    values = {
+        u'server_name':     dumps(adapter.server_name),
+        u'script_name':     dumps(adapter.script_name),
+        u'subdomain':       dumps(adapter.subdomain),
+        u'url_scheme':      dumps(adapter.url_scheme),
+        u'name':            name,
+        u'map_name':        map_name
+    }
+    return u'''\
+var %(name)s = %(map_name)s(
+    %(server_name)s,
+    %(script_name)s,
+    %(subdomain)s,
+    %(url_scheme)s
+);''' % values
+
+
+def js_to_url_function(converter):
+    """Get the JavaScript converter function from a rule."""
+    if hasattr(converter, 'js_to_url_function'):
+        data = converter.js_to_url_function()
+    else:
+        for cls in getmro(type(converter)):
+            if cls in js_to_url_functions:
+                data = js_to_url_functions[cls](converter)
+                break
+        else:
+            return 'encodeURIComponent'
+    return '(function(value) { %s })' % data
+
+
+def NumberConverter_js_to_url(conv):
+    if conv.fixed_digits:
+        return u'''\
+var result = value.toString();
+while (result.length < %s)
+    result = '0' + result;
+return result;''' % conv.fixed_digits
+    return u'return value.toString();'
+
+
+js_to_url_functions = {
+    NumberConverter:    NumberConverter_js_to_url
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/contrib/kickstart.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,282 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.contrib.kickstart
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    This module provides some simple shortcuts to make using Werkzeug
+    simpler for small scripts.
+
+    These improvements include predefied Request and Response objects as well
+    as a pre-defined Application object which all can be customized in child
+    classes of course. The Request and Reponse objects handle URL generation
+    as well as sessions via the werkzeug.contrib.sessions and is purely
+    optional.
+
+    There is also some integration of template engines. The template loaders
+    are of course not neccessary to use the template engines in Werkzeug, but
+    they provide a common interface. Currently supported template engines
+    include Werkzeug's minitmpl an Genshi. Support for other engines can be
+    added in a trivial way. These loaders provide a template interface similar
+    to the one that Django uses.
+
+    :copyright: 2007-2008 by Marek Kubica, Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+from os import path
+from werkzeug.wrappers import Request as RequestBase, Response as ResponseBase
+from werkzeug.templates import Template
+from werkzeug.exceptions import HTTPException
+from werkzeug.routing import RequestRedirect
+from werkzeug.contrib.sessions import FilesystemSessionStore
+
+__all__ = ['Request', 'Response', 'TemplateNotFound', 'TemplateLoader',
+           'GenshiTemplateLoader', 'Application']
+
+
+class Request(RequestBase):
+    """A handy subclass of the base request that adds a URL builder.
+    It when supplied a session store, it is also able to handle sessions.
+    """
+
+    def __init__(self, environ, url_map,
+            session_store=None, cookie_name=None):
+        # call the parent for initialization
+        RequestBase.__init__(self, environ)
+        # create an adapter
+        self.url_adapter = url_map.bind_to_environ(environ)
+        # create all stuff for sessions
+        self.session_store = session_store
+        self.cookie_name = cookie_name
+
+        if session_store is not None and cookie_name is not None:
+            if cookie_name in self.cookies:
+                # get the session out of the storage
+                self.session = session_store.get(self.cookies[cookie_name])
+            else:
+                # create a new session
+                self.session = session_store.new()
+
+    def url_for(self, callback, **values):
+        return self.url_adapter.build(callback, values)
+
+
+class Response(ResponseBase):
+    """
+    A subclass of base response which sets the default mimetype to text/html.
+    It the `Request` that came in is using Werkzeug sessions, this class
+    takes care of saving that session.
+    """
+    default_mimetype = 'text/html'
+
+    def __call__(self, environ, start_response):
+        # get the request object
+        request = environ['werkzeug.request']
+
+        if request.session_store is not None:
+            # save the session if neccessary
+            request.session_store.save_if_modified(request.session)
+
+            # set the cookie for the browser if it is not there:
+            if request.cookie_name not in request.cookies:
+                self.set_cookie(request.cookie_name, request.session.sid)
+
+        # go on with normal response business
+        return ResponseBase.__call__(self, environ, start_response)
+
+
+class Processor(object):
+    """A request and response processor - it is what Django calls a
+    middleware, but Werkzeug also includes straight-foward support for real
+    WSGI middlewares, so another name was chosen.
+
+    The code of this processor is derived from the example in the Werkzeug
+    trac, called `Request and Response Processor
+    <http://dev.pocoo.org/projects/werkzeug/wiki/RequestResponseProcessor>`_
+    """
+
+    def process_request(self, request):
+        return request
+
+    def process_response(self, request, response):
+        return response
+
+    def process_view(self, request, view_func, view_args, view_kwargs):
+        """process_view() is called just before the Application calls the
+        function specified by view_func.
+
+        If this returns None, the Application processes the next Processor,
+        and if it returns something else (like a Response instance), that
+        will be returned without any further processing.
+        """
+        return None
+
+    def process_exception(self, request, exception):
+        return None
+
+
+class Application(object):
+    """A generic WSGI application which can be used to start with Werkzeug in
+    an easy, straightforward way.
+    """
+
+    def __init__(self, name, url_map, session=False, processors=None):
+        # save the name and the URL-map, as it'll be needed later on
+        self.name = name
+        self.url_map = url_map
+        # save the list of processors if supplied
+        self.processors = processors or []
+        # create an instance of the storage
+        if session:
+            self.store = session
+        else:
+            self.store = None
+
+    def __call__(self, environ, start_response):
+        # create a request - with or without session support
+        if self.store is not None:
+            request = Request(environ, self.url_map,
+                session_store=self.store, cookie_name='%s_sid' % self.name)
+        else:
+            request = Request(environ, self.url_map)
+
+        # apply the request processors
+        for processor in self.processors:
+            request = processor.process_request(request)
+
+        try:
+            # find the callback to which the URL is mapped
+            callback, args = request.url_adapter.match(request.path)
+        except (HTTPException, RequestRedirect), e:
+            response = e
+        else:
+            # check all view processors
+            for processor in self.processors:
+                action = processor.process_view(request, callback, (), args)
+                if action is not None:
+                    # it is overriding the default behaviour, this is
+                    # short-circuiting the processing, so it returns here
+                    return action(environ, start_response)
+
+            try:
+                response = callback(request, **args)
+            except Exception, exception:
+                # the callback raised some exception, need to process that
+                for processor in reversed(self.processors):
+                    # filter it through the exception processor
+                    action = processor.process_exception(request, exception)
+                    if action is not None:
+                        # the exception processor returned some action
+                        return action(environ, start_response)
+                # still not handled by a exception processor, so re-raise
+                raise
+
+        # apply the response processors
+        for processor in reversed(self.processors):
+            response = processor.process_response(request, response)
+
+        # return the completely processed response
+        return response(environ, start_response)
+
+
+    def config_session(self, store, expiration='session'):
+        """
+        Configures the setting for cookies. You can also disable cookies by
+        setting store to None.
+        """
+        self.store = store
+        # expiration=session is the default anyway
+        # TODO: add settings to define the expiration date, the domain, the
+        # path any maybe the secure parameter.
+
+
+class TemplateNotFound(IOError, LookupError):
+    """
+    A template was not found by the template loader.
+    """
+
+    def __init__(self, name):
+        IOError.__init__(self, name)
+        self.name = name
+
+
+class TemplateLoader(object):
+    """
+    A simple loader interface for the werkzeug minitmpl
+    template language.
+    """
+
+    def __init__(self, search_path, encoding='utf-8'):
+        self.search_path = path.abspath(search_path)
+        self.encoding = encoding
+
+    def get_template(self, name):
+        """Get a template from a given name."""
+        filename = path.join(self.search_path, *[p for p in name.split('/')
+                                                 if p and p[0] != '.'])
+        if not path.exists(filename):
+            raise TemplateNotFound(name)
+        return Template.from_file(filename, self.encoding)
+
+    def render_to_response(self, *args, **kwargs):
+        """Load and render a template into a response object."""
+        return Response(self.render_to_string(*args, **kwargs))
+
+    def render_to_string(self, *args, **kwargs):
+        """Load and render a template into a unicode string."""
+        try:
+            template_name, args = args[0], args[1:]
+        except IndexError:
+            raise TypeError('name of template required')
+        return self.get_template(template_name).render(*args, **kwargs)
+
+
+class GenshiTemplateLoader(TemplateLoader):
+    """A unified interface for loading Genshi templates. Actually a quite thin
+    wrapper for Genshi's TemplateLoader.
+
+    It sets some defaults that differ from the Genshi loader, most notably
+    auto_reload is active. All imporant options can be passed through to
+    Genshi.
+    The default output type is 'html', but can be adjusted easily by changing
+    the `output_type` attribute.
+    """
+    def __init__(self, search_path, encoding='utf-8', **kwargs):
+        TemplateLoader.__init__(self, search_path, encoding)
+        # import Genshi here, because we don't want a general Genshi
+        # dependency, only a local one
+        from genshi.template import TemplateLoader as GenshiLoader
+        from genshi.template.loader import TemplateNotFound
+
+        self.not_found_exception = TemplateNotFound
+        # set auto_reload to True per default
+        reload_template = kwargs.pop('auto_reload', True)
+        # get rid of default_encoding as this template loaders overwrites it
+        # with the value of encoding
+        kwargs.pop('default_encoding', None)
+
+        # now, all arguments are clean, pass them on
+        self.loader = GenshiLoader(search_path, default_encoding=encoding,
+                auto_reload=reload_template, **kwargs)
+
+        # the default output is HTML but can be overridden easily
+        self.output_type = 'html'
+        self.encoding = encoding
+
+    def get_template(self, template_name):
+        """Get the template which is at the given name"""
+        try:
+            return self.loader.load(template_name, encoding=self.encoding)
+        except self.not_found_exception, e:
+            # catch the exception raised by Genshi, convert it into a werkzeug
+            # exception (for the sake of consistency)
+            raise TemplateNotFound(template_name)
+
+    def render_to_string(self, template_name, context=None):
+        """Load and render a template into an unicode string"""
+        # create an empty context if no context was specified
+        context = context or {}
+        tmpl = self.get_template(template_name)
+        # render the template into a unicode string (None means unicode)
+        return tmpl. \
+            generate(**context). \
+            render(self.output_type, encoding=None)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/contrib/limiter.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.contrib.limiter
+    ~~~~~~~~~~~~~~~~~~~~~~~~
+
+    A middleware that limits incoming data.  This works around problems
+    with trac or django because those stream into the memory directly.
+
+
+    :copyright: 2007 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+
+
+class LimitedStream(object):
+    """
+    Wraps a stream and doesn't read more than n bytes.
+    """
+
+    def __init__(self, environ, limit):
+        self._environ = environ
+        self._stream = environ['wsgi.input']
+        self._limit = min(limit, int(environ.get('CONTENT_LENGTH') or 0))
+        self._pos = 0
+
+    def read(self, size=None):
+        if self._pos >= self._limit:
+            return ''
+        if size is None:
+            size = self._limit
+        read = self._stream.read(min(self._limit - self._pos, size))
+        self._pos += len(read)
+        return read
+
+    def readline(self, *args):
+        if self._pos >= self._limit:
+            return ''
+        line = self._stream.readline(*args)
+        self.pos += len(line)
+        self.processed()
+        return line
+
+    def readlines(self, hint=None):
+        result = []
+        while self.pos < self._limit:
+            result.append(self.readline())
+        return result
+
+
+class StreamLimitMiddleware(object):
+    """
+    Limits the input stream to a given number of bytes.  This is useful if
+    you have a WSGI application that reads form data into memory (django for
+    example) and you don't want users to harm the server by uploading tons of
+    data.
+
+    Default is 10MB
+    """
+
+    def __init__(self, app, maximum_size=1024 * 1024 * 10):
+        self.app = app
+        self.maximum_size = maximum_size
+
+    def __call__(self, environ, start_response):
+        environ['wsgi.input'] = LimitedStream(environ, self.maximum_size)
+        return self.app(environ, start_response)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/contrib/profiler.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,94 @@
+# -*- coding: utf-8 -*-
+"""
+    inyoka.middlewares.profiler
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    Provides a WSGI Profiler middleware for finding bottlenecks.
+
+    :copyright: 2006-2007 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+import sys
+try:
+    try:
+        from cProfile import Profile
+    except ImportError:
+        from profile import Profile
+    from pstats import Stats
+    available = True
+except ImportError:
+    available = False
+
+
+class MergeStream(object):
+    """An object that redirects `write` calls to multiple streams.
+    Use this to log to both `sys.stdout` and a file::
+
+        f = file('profiler.log')
+        stream = MergeStream(sys.stdout, f)
+        profiler = ProfilerMiddleware(app, stream)
+    """
+
+    def __init__(self, *streams):
+        if not streams:
+            raise TypeError('at least one stream must be given')
+        self.streams = streams
+
+    def write(self, data):
+        for stream in self.streams:
+            stream.write(data)
+
+
+class ProfilerMiddleware(object):
+    """Simple profiler middleware."""
+
+    def __init__(self, app, stream=None,
+                 sort_by=('time', 'calls'), restrictions=()):
+        if not available:
+            raise RuntimeError('the profiler is not available because '
+                               'profile or pstat is not installed.')
+        self._app = app
+        self._stream = stream or sys.stdout
+        self._sort_by = sort_by
+        self._restrictions = restrictions
+
+    def __call__(self, environ, start_response):
+        response_body = []
+
+        def catching_start_response(status, headers, exc_info=None):
+            start_response(status, headers, exc_info)
+            return response_body.append
+
+        def runapp():
+            appiter = self._app(environ, catching_start_response)
+            response_body.extend(appiter)
+            if hasattr(appiter, 'close'):
+                appiter.close()
+
+        p = Profile()
+        p.runcall(runapp)
+        body = ''.join(response_body)
+        stats = Stats(p)
+        stats.sort_stats(*self._sort_by)
+
+        self._stream.write('-' * 80)
+        self._stream.write('\nPATH: %r\n' % environ.get('PATH_INFO'))
+        stats.print_stats(*self._restrictions)
+        self._stream.write('-' * 80 + '\n\n')
+
+        return [body]
+
+
+def make_action(app_factory, hostname='localhost', port=5000,
+                threaded=False, processes=1, stream=None,
+                sort_by=('time', 'calls'), restrictions=()):
+    """Return a new callback for werkzeug scripts that starts a local
+    server for profiling.
+    """
+    def action(hostname=('h', hostname), port=('p', port),
+               threaded=threaded, processes=processes):
+        """Start a new development server."""
+        from werkzeug.serving import run_simple
+        app = ProfilerMiddleware(app_factory(), stream, sort_by, restrictions)
+        run_simple(hostname, port, app, False, None, threaded, processes)
+    return action
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/contrib/reporterstream.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,87 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.contrib.reporterstream
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    This module implements a class that can wrap `wsgi.input` in order to
+    be informed about changes of the stream.  This is useful if you want
+    to display a progress bar for the upload.
+
+    :copyright: 2007 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+
+
+class BaseReporterStream(object):
+    """
+    This class can be used to wrap `wsgi.input` in order to be informed about
+    changes of the stream.
+
+    Usage::
+
+        from random import randrange
+
+        class ReporterStream(BaseReporterStream):
+
+            def __init__(self, environ):
+                super(ReporterStream, self).__init__(environ, 1024 * 16)
+                self.transport_id = randrange(0, 100000)
+
+            def processed(self):
+                s = self.environ['my.session.service']
+                s.store['upload/%s' % self.transport_id] = (self.pos, self.length)
+                s.flush()
+
+
+    And before accessing `request.form` or similar attributes add the stream:
+
+        stream = ReporterStream(environ)
+        environ['wsgi.input'] = stream
+    """
+
+    def __init__(self, environ, threshold):
+        self.threshold = threshold
+        self.length = int(environ.get('CONTENT_LENGTH') or 0)
+        self.pos = 0
+        self.environ = environ
+        self._stream = environ['wsgi.input']
+
+    def processed(self):
+        """Called after pos has changed for threshold or a line was read."""
+
+    def read(self, size=None):
+        length = self.length
+        threshold = self.threshold
+        buffer = []
+
+        if size is None:
+            while self.pos < length:
+                step = min(threshold, length - self.pos)
+                data = self._stream.read(step)
+                self.pos += step
+                self.processed()
+                buffer.append(data)
+        else:
+            read = 0
+            while read < size:
+                step = min(threshold, length - self.pos)
+                step = min(step, size)
+                data = self._stream.read(step)
+                self.pos += step
+                read += step
+                self.processed()
+                buffer.append(data)
+
+        return ''.join(buffer)
+
+    def readline(self, *args):
+        line = self._stream.readline(*args)
+        self.pos += len(line)
+        self.processed()
+        return line
+
+    def readlines(self, hint=None):
+        result = []
+        while self.pos < self.length:
+            result.append(self.readline())
+        return result
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/contrib/securecookie.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,235 @@
+# -*- coding: utf-8 -*-
+r"""
+    werkzeug.contrib.securecookie
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    This module implements a cookie that is not alterable from the client
+    because it adds a checksum the server checks for.  You can use it as
+    session replacement if all you have is a user id or something to mark
+    a logged in user.
+
+    Keep in mind that the data is still readable from the client as a
+    normal cookie is.  However you don't have to store and flush the
+    sessions you have at the server.
+
+    Example usage:
+
+        >>> from werkzeug.contrib.securecookie import SecureCookie
+        >>> x = SecureCookie({"foo": 42, "baz": (1, 2, 3)}, "deadbeef")
+
+    Dumping into a string so that one can store it in a cookie:
+
+        >>> value = x.serialize()
+
+    Loading from that string again:
+
+        >>> x = SecureCookie.unserialize(value, "deadbeef")
+        >>> x["baz"]
+        (1, 2, 3)
+
+    If someone modifies the cookie and the checksum is wrong the unserialize
+    method will fail silently and return a new empty `SecureCookie` object.
+
+    Keep in mind that the values will be visible in the cookie so do not
+    store data in a cookie you don't want the user to see.
+
+    Application Integration
+    =======================
+
+    If you are using the werkzeug request objects you could integrate the
+    secure cookie into your application like this::
+
+        from werkzeug import BaseRequest, cached_property
+        from werkzeug.contrib.securecookie import SecureCookie
+
+        # don' use this key but a different one.  you could just use
+        # os.unrandom(20) to get something random
+        SECRET_KEY = '\xfa\xdd\xb8z\xae\xe0}4\x8b\xea'
+
+        class Request(BaseRequest):
+
+            @cached_property
+            def client_session(self):
+                data = self.cookies.get('session_data')
+                if not data:
+                    return SecureCookie(secret_key=SECRET_KEY)
+                return SecureCookie.unserialize(data, SECRET_KEY)
+
+        def application(environ, start_response):
+            request = Request(environ, start_response)
+
+            # get a response object here
+            response = ...
+
+            if request.client_session.should_save:
+                session_data = request.client_session.serialize()
+                response.set_cookie('session_data', session_data,
+                                    httponly=True)
+            return response(environ, start_response)
+
+
+    :copyright: 2007 by Armin Ronacher, Thomas Johansson.
+    :license: BSD, see LICENSE for more details.
+"""
+try:
+    from hashlib import sha1
+except ImportError:
+    import sha as sha1
+from hmac import new as hmac
+from datetime import datetime
+from time import time, mktime, gmtime
+from random import Random
+from cPickle import loads, dumps, HIGHEST_PROTOCOL
+from werkzeug import url_quote_plus, url_unquote_plus
+from werkzeug.contrib.sessions import ModificationTrackingDict, generate_key
+
+
+class UnquoteError(Exception):
+    pass
+
+
+def pickle_quote(value):
+    """Pickle and url encode a value."""
+    result = None
+    for protocol in xrange(HIGHEST_PROTOCOL + 1):
+        data = ''.join(dumps(value, protocol).encode('base64').splitlines()).strip()
+        if result is None or len(result) > len(data):
+            result = data
+    return result
+
+
+def pickle_unquote(string):
+    """URL decode a string and load it into pickle"""
+    try:
+        return loads(string.decode('base64'))
+    # unfortunately pickle can cause pretty every error here.
+    # if we get one we catch it and convert it into an UnquoteError
+    except Exception, e:
+        raise UnquoteError(str(e))
+
+
+class SecureCookie(ModificationTrackingDict):
+    """Represents a secure cookie.  You can subclass this class and provide
+    an alternative mac method.  The import thing is that the mac method
+    is a function with a similar interface to the hashlib.  Required
+    methods are update() and digest().
+    """
+
+    # the hash method to use.  In python 2.5 and higher this is a callable
+    # that returns a new hashlib object or a module with a new method that
+    # creates such an object.  In python 2.4 and earlier only the module
+    # is supported.
+    hash_method = sha1
+
+    def __init__(self, data=None, secret_key=None, new=True):
+        ModificationTrackingDict.__init__(self, data or ())
+        self.secret_key = secret_key
+        self.new = new
+
+    def __repr__(self):
+        return '<%s %s%s>' % (
+            self.__class__.__name__,
+            dict.__repr__(self),
+            self.should_save and '*' or ''
+        )
+
+    def should_save(self):
+        """True if the session should be saved."""
+        return self.modified
+    should_save = property(should_save)
+
+    def serialize(self, expires=None):
+        """Serialize the secure cookie into a string.
+
+        If expires is provided, the session will be automatically invalidated
+        after expiration when you unseralize it. This provides better
+        protection against session cookie theft.
+        """
+        if self.secret_key is None:
+            raise RuntimeError('no secret key defined')
+        if expires:
+            if isinstance(expires, datetime):
+                expires = expires.utctimetuple()
+            elif isinstance(expires, (int, long, float)):
+                expires = gmtime(expires)
+            self['_expires'] = int(mktime(expires))
+        result = []
+        mac = hmac(self.secret_key, None, self.hash_method)
+        for key, value in self.iteritems():
+            result.append('%s=%s' % (
+                url_quote_plus(key),
+                pickle_quote(value)
+            ))
+            mac.update('|' + result[-1])
+        return '%s?%s' % (
+            mac.digest().encode('base64').strip(),
+            '&'.join(result)
+        )
+
+    def unserialize(cls, string, secret_key):
+        """Load the secure cookie from a serialized string."""
+        if isinstance(string, unicode):
+            string = string.encode('utf-8', 'ignore')
+        try:
+            base64_hash, data = string.split('?', 1)
+        except (ValueError, IndexError):
+            items = ()
+        else:
+            items = {}
+            mac = hmac(secret_key, None, cls.hash_method)
+            for item in data.split('&'):
+                mac.update('|' + item)
+                if not '=' in item:
+                    items = None
+                    break
+                key, value = item.split('=', 1)
+                # try to make the key a string
+                key = url_unquote_plus(key)
+                try:
+                    key = str(key)
+                except UnicodeError:
+                    pass
+                items[key] = value
+
+            # no parsing error and the mac looks okay, we can now
+            # sercurely unpickle our cookie.
+            try:
+                client_hash = base64_hash.decode('base64')
+            except Exception:
+                items = client_hash = None
+            if items is not None and client_hash == mac.digest():
+                try:
+                    for key, value in items.iteritems():
+                        items[key] = pickle_unquote(value)
+                except UnquoteError:
+                    items = ()
+                else:
+                    if '_expires' in items:
+                        if time() > items['_expires']:
+                            items = ()
+                        else:
+                            del items['_expires']
+            else:
+                items = ()
+        return cls(items, secret_key, False)
+    unserialize = classmethod(unserialize)
+
+    def load_cookie(cls, request, key='session', secret_key=None):
+        """Loads a SecureCookie from a cookie in request. If the cookie is not
+        set, a new SecureCookie instanced is returned.
+        """
+        data = request.cookies.get(key)
+        if not data:
+            return SecureCookie(secret_key=secret_key)
+        return SecureCookie.unserialize(data, secret_key)
+    load_cookie = classmethod(load_cookie)
+
+    def save_cookie(self, response, key='session', expires=None,
+                    session_expires=None, max_age=None, path='/', domain=None,
+                    secure=None, httponly=False, force=False):
+        """Saves the SecureCookie in a cookie on response."""
+        if force or self.should_save:
+            data = self.serialize(session_expires or expires)
+            response.set_cookie(key, data, expires=expires, max_age=max_age,
+                                path=path, domain=domain, secure=secure,
+                                httponly=httponly)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/contrib/sessions.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,287 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.contrib.sessions
+    ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    This module contains some helper classes that helps one to add session
+    support to a python WSGI application.
+
+    Example::
+
+        from werkzeug.contrib.sessions import SessionMiddleware, \
+             FilesystemSessionStore
+
+        app = SessionMiddleware(app, FilesystemSessionStore())
+
+    The current session will then appear in the WSGI environment as
+    `werkzeug.session`.  However it's recommended to not use the middleware
+    but the stores directly in the application.  However for very simple
+    scripts a middleware for sessions could be sufficient.
+
+    This module does not implement methods or ways to check if a session is
+    expired.  That should be done by a cronjob and storage specific.  For
+    example to prune unused filesystem sessions one could check the modified
+    time of the files.  It sessions are stored in the database the new()
+    method should add an expiration timestamp for the session.
+
+    For better flexibility it's recommended to not use the middleware but the
+    store and session object directly in the application dispatching::
+
+        session_store = FilesystemSessionStore()
+
+        def application(environ, start_response):
+            request = Request(environ)
+            sid = request.cookie.get('cookie_name')
+            if sid is None:
+                request.session = session_store.new()
+            else:
+                request.session = session_store.get(sid)
+            response = get_the_response_object(request)
+            if request.session.should_save:
+                session_store.save(request.session)
+                response.set_cookie('cookie_name', request.session.sid)
+            return response(environ, start_response)
+
+
+    :copyright: 2007 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+import re
+import os
+from os import path, unlink
+from time import time
+from random import Random, random
+try:
+    from hashlib import sha1
+except ImportError:
+    from sha import new as sha1
+from cPickle import dump, load, HIGHEST_PROTOCOL
+from werkzeug.utils import ClosingIterator, dump_cookie, parse_cookie
+
+
+_sha1_re = re.compile(r'^[a-fA-F0-9]{40}$')
+
+
+def _urandom():
+    if hasattr(os, 'urandom'):
+        return os.urandom(30)
+    return random()
+
+
+def generate_key(salt=None):
+    return sha1('%s%s%s' % (salt, time(), _urandom())).hexdigest()
+
+
+class ModificationTrackingDict(dict):
+    __slots__ = ('modified',)
+
+    def __init__(self, *args, **kwargs):
+        dict.__init__(self, *args, **kwargs)
+        self.modified = False
+
+    def __repr__(self):
+        return '<%s %s%s>' % (
+            self.__class__.__name__,
+            dict.__repr__(self)
+        )
+
+    def copy(self):
+        """Create a flat copy of the dict."""
+        missing = object()
+        result = object.__new__(self.__class__)
+        for name in self.__slots__:
+            val = getattr(self, name, missing)
+            if val is not missing:
+                setattr(result, name, val)
+        return result
+
+    def __copy__(self):
+        return self.copy()
+
+    def call_with_modification(f):
+        def oncall(self, *args, **kw):
+            try:
+                return f(self, *args, **kw)
+            finally:
+                self.modified = True
+        try:
+            oncall.__name__ = f.__name__
+            oncall.__doc__ = f.__doc__
+            oncall.__module__ = f.__module__
+        except:
+            pass
+        return oncall
+
+    __setitem__ = call_with_modification(dict.__setitem__)
+    __delitem__ = call_with_modification(dict.__delitem__)
+    clear = call_with_modification(dict.clear)
+    pop = call_with_modification(dict.pop)
+    popitem = call_with_modification(dict.popitem)
+    setdefault = call_with_modification(dict.setdefault)
+    update = call_with_modification(dict.update)
+    del call_with_modification
+
+
+class Session(ModificationTrackingDict):
+    """
+    Subclass of a dict that keeps track of direct object changes.  Changes
+    in mutable structures are not tracked, for those you have to set
+    `modified` to `True` by hand.
+    """
+    __slots__ = ModificationTrackingDict.__slots__ + ('sid', 'new')
+
+    def __init__(self, data, sid, new=False):
+        ModificationTrackingDict.__init__(self, data)
+        self.sid = sid
+        self.new = new
+
+    def __repr__(self):
+        return '<%s %s%s>' % (
+            self.__class__.__name__,
+            dict.__repr__(self),
+            self.should_save and '*' or ''
+        )
+
+    def should_save(self):
+        """True if the session should be saved."""
+        return self.modified or self.new
+    should_save = property(should_save)
+
+
+class SessionStore(object):
+    """Baseclass for all session stores.  The Werkzeug contrib module does not
+    implement any useful stores beside the filesystem store, application
+    developers are encouraged to create their own stores.
+    """
+
+    def __init__(self, session_class=None):
+        if session_class is None:
+            session_class = Session
+        self.session_class = session_class
+
+    def is_valid_key(self, key):
+        """Check if a key has the correct format."""
+        return _sha1_re.match(key) is not None
+
+    def generate_key(self, salt=None):
+        """Simple function that generates a new session key."""
+        return generate_key(salt)
+
+    def new(self):
+        """Generate a new session."""
+        return self.session_class({}, self.generate_key(), True)
+
+    def save(self, session):
+        """Save a session."""
+
+    def save_if_modified(self, session):
+        """Save if a session class wants an update."""
+        if session.should_save:
+            self.save(session)
+
+    def delete(self, session):
+        """Delete a session."""
+
+    def get(self, sid):
+        """Get a session for this sid or a new session object.  This method
+        has to check if the session key is valid and create a new session if
+        that wasn't the case.
+        """
+        return self.session_class({}, sid, True)
+
+
+class FilesystemSessionStore(SessionStore):
+    """Simple example session store that saves session on the filesystem like
+    PHP does.
+    """
+
+    def __init__(self, path=None, filename_template='werkzeug_%s.sess',
+                 session_class=Session):
+        SessionStore.__init__(self, session_class)
+        if path is None:
+            from tempfile import gettempdir
+            path = gettempdir()
+        self.path = path
+        self.filename_template = filename_template
+
+    def get_session_filename(self, sid):
+        return path.join(self.path, self.filename_template % sid)
+
+    def save(self, session):
+        f = file(self.get_session_filename(session.sid), 'wb')
+        try:
+            dump(dict(session), f, HIGHEST_PROTOCOL)
+        finally:
+            f.close()
+
+    def delete(self, session):
+        fn = self.get_session_filename(session.sid)
+        try:
+            unlink(fn)
+        except OSError:
+            pass
+
+    def get(self, sid):
+        fn = self.get_session_filename(sid)
+        if not self.is_valid_key(sid) or not path.exists(fn):
+            return self.new()
+        else:
+            f = file(fn, 'rb')
+            try:
+                data = load(f)
+            finally:
+                f.close()
+        return self.session_class(data, sid, False)
+
+
+class SessionMiddleware(object):
+    """A simple middleware that puts the session object of a store provided
+    into the WSGI environ.  It automatically sets cookies and restores
+    sessions.
+
+    However a middleware is not the preferred solution because it won't be as
+    fast as sessions managed by the application itself and will put a key into
+    the WSGI environment only relevant for the application which is against
+    the concept of WSGI.
+    """
+
+    def __init__(self, app, store, cookie_name='session_id',
+                 cookie_age=None, cookie_expires=None, cookie_path='/',
+                 cookie_domain=None, cookie_secure=None,
+                 cookie_httponly=False, environ_key='werkzeug.session'):
+        """The cookie parameters are the same as for the `dump_cookie`
+        function just prefixed with "cookie_".  Additionally "max_age" is
+        called "cookie_age" and not "cookie_max_age" because of backwards
+        compatibility.
+        """
+        self.app = app
+        self.store = store
+        self.cookie_name = cookie_name
+        self.cookie_age = cookie_age
+        self.cookie_expires = cookie_expires
+        self.cookie_path = cookie_path
+        self.cookie_domain = cookie_domain
+        self.cookie_secure = cookie_secure
+        self.cookie_httponly = cookie_httponly
+        self.environ_key = environ_key
+
+    def __call__(self, environ, start_response):
+        cookie = parse_cookie(environ.get('HTTP_COOKIE', ''))
+        sid = cookie.get(self.cookie_name, None)
+        if sid is None:
+            session = self.store.new()
+        else:
+            session = self.store.get(sid)
+        environ[self.environ_key] = session
+
+        def injecting_start_response(status, headers, exc_info=None):
+            if session.should_save:
+                self.store.save(session)
+                headers.append(('Set-Cookie', dump_cookie(self.cookie_name,
+                                session.sid, self.cookie_age,
+                                self.cookie_expires, self.cookie_path,
+                                self.cookie_domain, self.cookie_secure,
+                                self.cookie_httponly)))
+            return start_response(status, headers, exc_info)
+        return ClosingIterator(self.app(environ, injecting_start_response),
+                               lambda: self.store.save_if_modified(session))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/contrib/testtools.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,63 @@
+"""
+    werkzeug.contrib.testtools
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+    This Module implements a extended wrappers for simplified Testing
+
+    `TestResponse`
+        a response wrapper wich adds various cached attributes for
+        simplified assertions on various contenttypes
+
+
+    :copyright: 2007 by Ronny Pfannschmidt.
+    :license: BSD, see LICENSE for more details.
+"""
+from werkzeug import Response, cached_property, import_string
+
+
+class ContentAccessors(object):
+    """
+    A mixin class for response objects that provides a couple of useful
+    accessors for unittesting.
+    """
+
+    def xml(self):
+        """Get an etree if possible."""
+        if 'xml' not in self.mimetype:
+            raise AttributeError(
+                'Not a XML response (Content-Type: %s)'
+                % self.mimetype)
+        for module in ['xml.etree.ElementTree', 'ElementTree',
+                       'elementtree.ElementTree']:
+            etree = import_string(module, silent=True)
+            if etree is not None:
+                return etree.XML(self.body)
+        raise RuntimeError('You must have ElementTree installed '
+                           'to use TestResponse.xml')
+    xml = cached_property(xml)
+
+    def lxml(self):
+        """Get an lxml etree if possible."""
+        if ('html' not in self.mimetype and 'xml' not in self.mimetype):
+            raise AttributeError('Not an HTML/XML response')
+        from lxml import etree
+        try:
+            from lxml.html import fromstring
+        except ImportError:
+            fromstring = etree.HTML
+        if self.mimetype=='text/html':
+            return fromstring(self.data)
+        return etree.XML(self.data)
+    lxml = cached_property(lxml)
+
+    def json(self):
+        """Get the result of simplejson.loads if possible."""
+        if 'json' not in self.mimetype:
+            raise AttributeError('Not a JSON response')
+        from simplejson import loads
+        return loads(self.data)
+    json = cached_property(json)
+
+
+class TestResponse(Response, ContentAccessors):
+    """Pass this to `werkzeug.test.Client` for easier unittesting."""
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/debug/__init__.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,148 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.debug
+    ~~~~~~~~~~~~~~
+
+    WSGI application traceback debugger.
+
+    :copyright: 2008 by Georg Brandl, Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+from os.path import join, dirname, basename, isfile
+from mimetypes import guess_type
+from werkzeug.wrappers import BaseRequest as Request, BaseResponse as Response
+from werkzeug.debug.repr import debug_repr
+from werkzeug.debug.tbtools import get_current_traceback
+from werkzeug.debug.console import Console
+from werkzeug.debug.utils import render_template
+
+
+class _ConsoleFrame(object):
+    """Helper class so that we can reuse the frame console code for the
+    standalone console.
+    """
+
+    def __init__(self, namespace):
+        self.console = Console(namespace)
+        self.id = 0
+
+
+class DebuggedApplication(object):
+    """Enables debugging support for a given application::
+
+        from werkzeug.debug import DebuggedApplication
+        from myapp import app
+        app = DebuggedApplication(app, evalex=True)
+
+    The `evalex` keyword argument allows evaluating expressions in a
+    traceback's frame context.
+
+    THIS IS A GAPING SECURITY HOLE IF PUBLICLY ACCESSIBLE!
+    """
+
+    def __init__(self, app, evalex=False, request_key='werkzeug.request',
+                 console_path='/console', console_init_func=dict,
+                 show_hidden_frames=False):
+        self.app = app
+        self.evalex = evalex
+        self.frames = {}
+        self.tracebacks = {}
+        self.request_key = request_key
+        self.console_path = console_path
+        self.console_init_func = console_init_func
+        self.show_hidden_frames = show_hidden_frames
+
+    def debug_application(self, environ, start_response):
+        """Run the application and conserve the traceback frames."""
+        app_iter = None
+        try:
+            app_iter = self.app(environ, start_response)
+            for item in app_iter:
+                yield item
+            if hasattr(app_iter, 'close'):
+                app_iter.close()
+        except:
+            if hasattr(app_iter, 'close'):
+                app_iter.close()
+            traceback = get_current_traceback(skip=1, show_hidden_frames=
+                                              self.show_hidden_frames)
+            for frame in traceback.frames:
+                self.frames[frame.id] = frame
+            self.tracebacks[traceback.id] = traceback
+
+            try:
+                start_response('500 INTERNAL SERVER ERROR', [
+                    ('Content-Type', 'text/html; charset=utf-8')
+                ])
+            except:
+                # if we end up here there has been output but an error
+                # occurred.  in that situation we can do nothing fancy any
+                # more, better log something into the error log and fall
+                # back gracefully.
+                environ['wsgi.errors'].write(
+                    '\nDebugging middlware catched exception in streamed '
+                    'reponse a point where response headers were already '
+                    'sent.\n')
+                traceback.log(environ['wsgi.errors'])
+                return
+
+            yield traceback.render_full(evalex=self.evalex) \
+                           .encode('utf-8', 'replace')
+            traceback.log(environ['wsgi.errors'])
+
+    def execute_command(self, request, command, frame):
+        """Execute a command in a console."""
+        return Response(frame.console.eval(command), mimetype='text/html')
+
+    def display_console(self, request):
+        """Display a standalone shell."""
+        if 0 not in self.frames:
+            self.frames[0] = _ConsoleFrame(self.console_init_func())
+        return Response(render_template('console.html'), mimetype='text/html')
+
+    def paste_traceback(self, request, traceback):
+        """Paste the traceback and return a JSON response."""
+        paste_id = traceback.paste()
+        return Response('{"url": "http://paste.pocoo.org/show/%d/", "id": %d}'
+                        % (paste_id, paste_id), mimetype='application/json')
+
+    def get_source(self, request, frame):
+        """Render the source viewer."""
+        return Response(frame.render_source(), mimetype='text/html')
+
+    def get_resource(self, request, filename):
+        """Return a static resource from the shared folder."""
+        filename = join(dirname(__file__), 'shared', basename(filename))
+        if isfile(filename):
+            mimetype = guess_type(filename)[0] or 'application/octet-stream'
+            f = file(filename, 'rb')
+            try:
+                return Response(f.read(), mimetype=mimetype)
+            finally:
+                f.close()
+        return Response('Not Found', status=404)
+
+    def __call__(self, environ, start_response):
+        """Dispatch the requests."""
+        # important: don't ever access a function here that reads the incoming
+        # form data!  Otherwise the application won't have access to that data
+        # any more!
+        request = Request(environ)
+        response = self.debug_application
+        if self.evalex and self.console_path is not None and \
+           request.path == self.console_path:
+            response = self.display_console(request)
+        elif request.path.rstrip('/').endswith('/__debugger__'):
+            cmd = request.args.get('cmd')
+            arg = request.args.get('f')
+            traceback = self.tracebacks.get(request.args.get('tb', type=int))
+            frame = self.frames.get(request.args.get('frm', type=int))
+            if cmd == 'resource' and arg:
+                response = self.get_resource(request, arg)
+            elif cmd == 'paste' and traceback is not None:
+                response = self.paste_traceback(request, traceback)
+            elif cmd == 'source' and frame:
+                response = self.get_source(request, frame)
+            elif self.evalex and cmd is not None and frame is not None:
+                response = self.execute_command(request, cmd, frame)
+        return response(environ, start_response)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/debug/console.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,192 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.debug.console
+    ~~~~~~~~~~~~~~~~~~~~~~
+
+    Interactive console support.
+
+    :copyright: Copyright 2008 by Armin Ronacher.
+    :license: BSD.
+"""
+import sys
+import code
+from types import CodeType
+from cgi import escape
+from werkzeug.local import Local
+from werkzeug.debug.repr import debug_repr, dump, helper
+from werkzeug.debug.utils import render_template
+
+
+_local = Local()
+
+
+class HTMLStringO(object):
+    """A StringO version that HTML escapes on write."""
+
+    def __init__(self):
+        self._buffer = []
+
+    def isatty(self):
+        return False
+
+    def close(self):
+        pass
+
+    def reset(self):
+        val = ''.join(self._buffer)
+        del self._buffer[:]
+        return val
+
+    def _write(self, x):
+        if isinstance(x, str):
+            x = x.decode('utf-8', 'replace')
+        self._buffer.append(x)
+
+    def write(self, x):
+        self._write(escape(x))
+
+    def writelines(self, x):
+        self._write(escape(''.join(x)))
+
+
+class ThreadedStream(object):
+    """Thread-local wrapper for sys.stdout for the interactive console."""
+
+    def push():
+        if sys.stdout is sys.__stdout__:
+            sys.stdout = ThreadedStream()
+        _local.stream = HTMLStringO()
+    push = staticmethod(push)
+
+    def fetch():
+        try:
+            stream = _local.stream
+        except AttributeError:
+            return ''
+        return stream.reset()
+    fetch = staticmethod(fetch)
+
+    def displayhook(obj):
+        try:
+            stream = _local.stream
+        except AttributeError:
+            return _displayhook(obj)
+        # stream._write bypasses escaping as debug_repr is
+        # already generating HTML for us.
+        if obj is not None:
+            stream._write(debug_repr(obj))
+    displayhook = staticmethod(displayhook)
+
+    def __setattr__(self, name, value):
+        raise AttributeError('read only attribute %s' % name)
+
+    def __dir__(self):
+        return dir(sys.__stdout__)
+
+    def __getattribute__(self, name):
+        if name == '__members__':
+            return dir(sys.__stdout__)
+        try:
+            stream = _local.stream
+        except AttributeError:
+            stream = sys.__stdout__
+        return getattr(stream, name)
+
+    def __repr__(self):
+        return repr(sys.__stdout__)
+
+
+# add the threaded stream as display hook
+_displayhook = sys.displayhook
+sys.displayhook = ThreadedStream.displayhook
+
+
+class _ConsoleLoader(object):
+
+    def __init__(self):
+        self._storage = {}
+
+    def register(self, code, source):
+        self._storage[id(code)] = source
+        # register code objects of wrapped functions too.
+        for var in code.co_consts:
+            if isinstance(var, CodeType):
+                self._storage[id(var)] = source
+
+    def get_source_by_code(self, code):
+        try:
+            return self._storage[id(code)]
+        except KeyError:
+            pass
+
+
+def _wrap_compiler(console):
+    compile = console.compile
+    def func(source, filename, symbol):
+        code = compile(source, filename, symbol)
+        console.loader.register(code, source)
+        return code
+    console.compile = func
+
+
+class _InteractiveConsole(code.InteractiveInterpreter):
+
+    def __init__(self, globals, locals):
+        code.InteractiveInterpreter.__init__(self, locals)
+        self.globals = dict(globals)
+        self.globals['dump'] = dump
+        self.globals['help'] = helper
+        self.globals['__loader__'] = self.loader = _ConsoleLoader()
+        self.more = False
+        self.buffer = []
+        _wrap_compiler(self)
+
+    def runsource(self, source):
+        source = source.rstrip() + '\n'
+        ThreadedStream.push()
+        prompt = self.more and '... ' or '>>> '
+        try:
+            source_to_eval = ''.join(self.buffer + [source])
+            if code.InteractiveInterpreter.runsource(self,
+               source_to_eval, '<debugger>', 'single'):
+                self.more = True
+                self.buffer.append(source)
+            else:
+                self.more = False
+                del self.buffer[:]
+        finally:
+            output = ThreadedStream.fetch()
+        return prompt + source + output
+
+    def runcode(self, code):
+        try:
+            exec code in self.globals, self.locals
+        except:
+            self.showtraceback()
+
+    def showtraceback(self):
+        from werkzeug.debug.tbtools import get_current_traceback
+        tb = get_current_traceback(skip=1)
+        sys.stdout._write(tb.render_summary())
+
+    def showsyntaxerror(self, filename=None):
+        from werkzeug.debug.tbtools import get_current_traceback
+        tb = get_current_traceback(skip=4)
+        sys.stdout._write(tb.render_summary())
+
+    def write(self, data):
+        sys.stdout.write(data)
+
+
+class Console(object):
+    """An interactive console."""
+
+    def __init__(self, globals=None, locals=None):
+        if locals is None:
+            locals = {}
+        if globals is None:
+            globals = {}
+        self._ipy = _InteractiveConsole(globals, locals)
+
+    def eval(self, code):
+        return self._ipy.runsource(code)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/debug/render.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.debug.render
+    ~~~~~~~~~~~~~~~~~~~~~
+
+    Render the traceback debugging page.
+
+    :copyright: 2007 by Georg Brandl, Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+import pprint
+from os.path import dirname, join
+
+from werkzeug.templates import Template
+from werkzeug.debug.util import Namespace
+
+
+def get_template(name):
+    return Template.from_file(join(dirname(__file__), 'shared', name),
+                              unicode_mode=False, errors='ignore')
+
+
+def load_resource(res):
+    try:
+        f = file(join(dirname(__file__), 'shared', res))
+    except IOError:
+        return ''
+    try:
+        return f.read()
+    finally:
+        f.close()
+
+
+t_body = get_template('body.tmpl')
+t_codetable = get_template('codetable.tmpl')
+t_vartable = get_template('vartable.tmpl')
+
+
+def code_table(frame):
+    lines = []
+    lineno = frame['context_lineno']
+    if lineno is not None:
+        lineno += 1
+        for l in frame['pre_context']:
+            lines.append(Namespace(mode='pre', lineno=lineno, code=l))
+            lineno += 1
+        lines.append(Namespace(mode='cur', lineno=lineno,
+                               code=frame['context_line']))
+        lineno += 1
+        for l in frame['post_context']:
+            lines.append(Namespace(mode='post', lineno=lineno, code=l))
+            lineno += 1
+    else:
+        lines.append(Namespace(mode='cur', lineno=1,
+                               code='Sourcecode not available'))
+
+    return t_codetable.render(lines=lines)
+
+
+def var_table(var):
+    def safe_pformat(x):
+        try:
+            lines = pprint.pformat(x).splitlines()
+        except:
+            return '?'
+        tmp = []
+        for line in lines:
+            if len(line) > 79:
+                line = line[:79] + '...'
+            tmp.append(line)
+        return '\n'.join(tmp)
+
+    # dicts
+    if isinstance(var, dict) or hasattr(var, 'items'):
+        value = var.items()
+        if not value:
+            typ = 'empty'
+        else:
+            typ = 'dict'
+            value.sort()
+            value = [(repr(key), safe_pformat(val)) for key, val in value]
+
+    # lists
+    elif isinstance(var, list):
+        if not var:
+            typ = 'empty'
+        else:
+            typ = 'list'
+        value = [safe_pformat(item) for item in var]
+
+    # others
+    else:
+        typ = 'simple'
+        value = repr(var)
+
+    return t_vartable.render(type=typ, value=value)
+
+
+def debug_page(context):
+    tc = context.to_dict()
+    tc['var_table'] = var_table
+    tc['code_table'] = code_table
+    return t_body.render(tc)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/debug/repr.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,245 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.debug.repr
+    ~~~~~~~~~~~~~~~~~~~
+
+    This module implements object representations for debugging purposes.
+    Unlike the default repr these reprs expose a lot more information and
+    produce HTML instead of ASCII.
+
+    Together with the CSS and JavaScript files of the debugger this gives
+    a colorful and more compact output.
+
+    :copyright: Copyright 2008 by Armin Ronacher.
+    :license: BSD.
+"""
+import sys
+import re
+from types import InstanceType
+from traceback import format_exception_only
+try:
+    from collections import deque
+except ImportError:
+    deque = None
+from cgi import escape
+try:
+    set
+except NameError:
+    from sets import Set as set, ImmutableSet as frozenset
+from werkzeug.debug.utils import render_template
+
+
+missing = object()
+_paragraph_re = re.compile(r'(?:\r\n|\r|\n){2,}')
+RegexType = type(_paragraph_re)
+
+
+def debug_repr(obj):
+    """Creates a debug repr of an object as HTML unicode string."""
+    return DebugReprGenerator().repr(obj)
+
+
+def dump(obj=missing):
+    """Print the object details to stdout._write (for the interactive
+    console of the web debugger.
+    """
+    gen = DebugReprGenerator()
+    if obj is missing:
+        rv = gen.dump_locals(sys._getframe(1).f_locals)
+    else:
+        rv = gen.dump_object(obj)
+    sys.stdout._write(rv)
+
+
+class _Helper(object):
+    """Displays an HTML version of the normal help, for the interactive
+    debugger only because it requirse a patched sys.stdout.
+    """
+
+    def __call__(self, topic=None):
+        sys.stdout._write(self.get_help(topic))
+
+    def get_help(self, topic):
+        title = text = None
+        if topic is not None:
+            import pydoc
+            pydoc.help(topic)
+            rv = sys.stdout.reset().decode('utf-8', 'ignore')
+            paragraphs = _paragraph_re.split(rv)
+            if len(paragraphs) > 1:
+                title = paragraphs[0]
+                text = '\n\n'.join(paragraphs[1:])
+            else:
+                title = 'Help'
+                text = paragraphs[0]
+        return render_template('help_command.html', title=title, text=text)
+
+helper = _Helper()
+
+
+def _add_subclass_info(inner, obj, base):
+    if isinstance(base, tuple):
+        for base in base:
+            if type(obj) is base:
+                return inner
+    elif type(obj) is base:
+        return inner
+    module = ''
+    if obj.__class__.__module__ not in ('__builtin__', 'exceptions'):
+        module = '<span class="module">%s.</span>' % obj.__class__.__module__
+    return '%s%s(%s)' % (module, obj.__class__.__name__, inner)
+
+
+class DebugReprGenerator(object):
+
+    def __init__(self):
+        self._stack = []
+
+    def _sequence_repr_maker(left, right, base=object(), limit=8):
+        def proxy(self, obj, recursive):
+            if recursive:
+                return _add_subclass_info(left + '...' + right, obj, base)
+            buf = [left]
+            have_extended_section = False
+            for idx, item in enumerate(obj):
+                if idx:
+                    buf.append(', ')
+                if idx == limit:
+                    buf.append('<span class="extended">')
+                    have_extended_section = True
+                buf.append(self.repr(item))
+            if have_extended_section:
+                buf.append('</span>')
+            buf.append(right)
+            return _add_subclass_info(u''.join(buf), obj, base)
+        return proxy
+
+    list_repr = _sequence_repr_maker('[', ']', list)
+    tuple_repr = _sequence_repr_maker('(', ')', tuple)
+    set_repr = _sequence_repr_maker('set([', '])', set)
+    frozenset_repr = _sequence_repr_maker('frozenset([', '])', frozenset)
+    if deque is not None:
+        deque_repr = _sequence_repr_maker('<span class="module">collections.'
+                                          '</span>deque([', '])', deque)
+    del _sequence_repr_maker
+
+    def regex_repr(self, obj):
+        pattern = repr(obj.pattern).decode('string-escape', 'ignore')
+        if pattern[:1] == 'u':
+            pattern = 'ur' + pattern[1:]
+        else:
+            pattern = 'r' + pattern
+        return u're.compile(<span class="string regex">%s</span>)' % pattern
+
+    def string_repr(self, obj, limit=70):
+        buf = ['<span class="string">']
+        escaped = escape(obj)
+        a = repr(escaped[:limit])
+        b = repr(escaped[limit:])
+        if isinstance(obj, unicode):
+            buf.append('u')
+            a = a[1:]
+            b = b[1:]
+        if b != "''":
+            buf.extend((a[:-1], '<span class="extended">', b[1:], '</span>'))
+        else:
+            buf.append(a)
+        buf.append('</span>')
+        return _add_subclass_info(u''.join(buf), obj, (str, unicode))
+
+    def dict_repr(self, d, recursive, limit=5):
+        if recursive:
+            return _add_subclass_info(u'{...}', d, dict)
+        buf = ['{']
+        have_extended_section = False
+        for idx, (key, value) in enumerate(d.iteritems()):
+            if idx:
+                buf.append(', ')
+            if idx == limit - 1:
+                buf.append('<span class="extended">')
+                have_extended_section = True
+            buf.append('<span class="pair"><span class="key">%s</span>: '
+                       '<span class="value">%s</span></span>' %
+                       (self.repr(key), self.repr(value)))
+        if have_extended_section:
+            buf.append('</span>')
+        buf.append('}')
+        return _add_subclass_info(u''.join(buf), d, dict)
+
+    def object_repr(self, obj):
+        return u'<span class="object">%s</span>' % \
+               escape(repr(obj).decode('utf-8', 'replace'))
+
+    def dispatch_repr(self, obj, recursive):
+        if obj is helper:
+            return helper.get_help(None)
+        if isinstance(obj, (int, long, float, complex)):
+            return u'<span class="number">%r</span>' % obj
+        if isinstance(obj, basestring):
+            return self.string_repr(obj)
+        if isinstance(obj, RegexType):
+            return self.regex_repr(obj)
+        if isinstance(obj, list):
+            return self.list_repr(obj, recursive)
+        if isinstance(obj, tuple):
+            return self.tuple_repr(obj, recursive)
+        if isinstance(obj, set):
+            return self.set_repr(obj, recursive)
+        if isinstance(obj, frozenset):
+            return self.frozenset_repr(obj, recursive)
+        if isinstance(obj, dict):
+            return self.dict_repr(obj, recursive)
+        if deque is not None and isinstance(obj, deque):
+            return self.deque_repr(obj, recursive)
+        return self.object_repr(obj)
+
+    def fallback_repr(self):
+        try:
+            info = ''.join(format_exception_only(*sys.exc_info()[:2]))
+        except:
+            info = '?'
+        return u'<span class="brokenrepr">&lt;broken repr (%s)&gt;' \
+               u'</span>' % escape(info.decode('utf-8', 'ignore').strip())
+
+    def repr(self, obj):
+        recursive = False
+        for item in self._stack:
+            if item is obj:
+                recursive = True
+                break
+        self._stack.append(obj)
+        try:
+            try:
+                return self.dispatch_repr(obj, recursive)
+            except:
+                return self.fallback_repr()
+        finally:
+            self._stack.pop()
+
+    def dump_object(self, obj):
+        repr = items = None
+        if isinstance(obj, dict):
+            title = 'Contents of'
+            items = []
+            for key, value in obj.iteritems():
+                if not isinstance(key, basestring):
+                    items = None
+                    break
+                items.append((key, self.repr(value)))
+        if items is None:
+            items = []
+            repr = self.repr(obj)
+            for key in dir(obj):
+                try:
+                    items.append((key, self.repr(getattr(obj, key))))
+                except:
+                    pass
+            title = 'Details for'
+        title += ' ' + object.__repr__(obj)[1:-1]
+        return render_template('dump_object.html', items=items,
+                               title=title, repr=repr)
+
+    def dump_locals(self, d):
+        items = [(key, self.repr(value)) for key, value in d.items()]
+        return render_template('dump_object.html', items=items,
+                               title='Local variables in frame', repr=None)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/debug/shared/body.tmpl	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+  <head>
+    <title>$escape(exception_type) in $escape(last_frame['basename']) (Werkzeug Debugger)</title>
+    <link rel="stylesheet" href="__traceback__?resource=style.css&amp;mimetype=text/css" type="text/css">
+    <script type="text/javascript" src="__traceback__?resource=jquery.js&amp;mimetype=text/javascript"></script>
+    <script type="text/javascript" src="__traceback__?resource=debugger.js&amp;mimetype=text/javascript"></script>
+  </head>
+  <body>
+    <div class="traceback_wrapper">
+      <h1>$escape(exception_type)</h1>
+      <p class="errormsg">$escape(exception_value)</p>
+
+      <p class="errorline">
+        $escape(last_frame['filename']) in
+        $escape(last_frame['function']),
+        line $last_frame['lineno']
+      </p>
+
+      <h2 onclick="changeTB()" class="tb">Traceback <span>(toggle raw view)</span></h2>
+      <div id="interactive">
+        <p class="text">A problem occurred in your Python WSGI application.
+          Here is the sequence of function calls leading up to the error, in the order
+          they occurred. Activate a code line to toggle context lines.</p>
+
+      <% for num, frame in enumerate(frames) %>
+        <div class="frame" id="frame-$num">
+          <h3 class="fn"><em>$escape(frame['function'])</em> in <tt>$escape(frame['filename'])</tt></h3>
+          <a class="locals" href="javascript:toggleFrameVars($num)">[inspect]</a>
+          <% if evalex %><a class="eval" href="javascript:toggleInterpreter($num)">[console]</a><% endif %>
+          $code_table(frame)
+          $var_table(frame['vars'])
+          <% if evalex %>
+            <form class="exec_code" action="">
+              <pre class="output">[console ready]</pre>
+              <input type="hidden" name="tb" value="$tb_uid">
+              <input type="hidden" name="frame" value="$frame['frame_uid']">
+              <input type="text" name="cmd" class="input" value="">
+            </form>
+          <% endif %>
+        </div>
+      <% endfor %>
+      </div>
+
+      <div id="plain">
+        <p class="text">Here is the plain Python traceback for copy and paste:</p>
+        <pre class="plain">$escape(plaintb)</pre>
+        <p class="text pastebininfo">
+          <a href="javascript:pasteIt()">Create a new Paste</a> with
+          this traceback in the lodgeit pastebin.
+        </p>
+      </div>
+
+      <% if req_vars %>
+        <h2>Request Data</h2>
+        <p class="text">The following list contains all important request variables.
+          Select a header to expand the list.</p>
+        <% for num, (key, info) in enumerate(req_vars) %>
+          <dl>
+            <dt onclick="toggleTableVars($num)">$escape(key)</dt>
+            <dd id="tvar-$num">$var_table(info)</dd>
+          </dl>
+        <% endfor %>
+      <% endif %>
+    </div>
+
+    <div id="footer">
+      Brought to you by <span class="arthur">DON'T PANIC</span>, your friendly
+      Werkzeug powered traceback interpreter.
+    </div>
+  </body>
+</html>
+
+<!-- Plain traceback:
+
+<%py
+  import re
+  print re.sub('-{2,}', '-', plaintb)
+%>
+-->
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/debug/shared/codetable.tmpl	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,8 @@
+<table class="code">
+<% for line in lines %>
+  <tr class="$line.mode">
+    <td class="lineno">$line.lineno</td>
+    <td class="code">$line.code</td>
+  </tr>
+<% endfor %>
+</table>
Binary file MoinMoin/support/werkzeug/debug/shared/console.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/debug/shared/debugger.js	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,186 @@
+$(function() {
+  var sourceView = null;
+
+  /**
+   * if we are in console mode, show the console.
+   */
+  if (CONSOLE_MODE && EVALEX) {
+    openShell(null, $('div.console div.inner').empty(), 0);
+  }
+
+  $('div.traceback div.frame').each(function() {
+    var
+      target = $('pre', this)
+        .click(function() {
+          sourceButton.click();
+        }),
+      consoleNode = null, source = null,
+      frameID = this.id.substring(6);
+
+    /**
+     * Add an interactive console to the frames
+     */
+    if (EVALEX)
+      $('<img src="./__debugger__?cmd=resource&f=console.png">')
+        .attr('title', 'Open an interactive python shell in this frame')
+        .click(function() {
+          consoleNode = openShell(consoleNode, target, frameID);
+          return false;
+        })
+        .prependTo(target);
+
+    /**
+     * Show sourcecode
+     */
+    var sourceButton = $('<img src="./__debugger__?cmd=resource&f=source.png">')
+      .attr('title', 'Display the sourcecode for this frame')
+      .click(function() {
+        if (!sourceView)
+          $('h2', sourceView =
+            $('<div class="box"><h2>View Source</h2><div class="sourceview">' +
+              '<table></table></div>')
+              .insertBefore('div.explanation'))
+            .css('cursor', 'pointer')
+            .click(function() {
+              sourceView.slideUp('fast');
+            });
+        $.get('./__debugger__', {cmd: 'source', frm: frameID}, function(data) {
+          $('table', sourceView)
+            .replaceWith(data);
+          if (!sourceView.is(':visible'))
+            sourceView.slideDown('fast', function() {
+              focusSourceBlock();
+            });
+          else
+            focusSourceBlock();
+        });
+        return false;
+      })
+      .prependTo(target);
+  });
+
+  /**
+   * toggle traceback types on click.
+   */
+  $('h2.traceback').click(function() {
+    $(this).next().slideToggle('fast');
+    $('div.plain').slideToggle('fast');
+  }).css('cursor', 'pointer');
+  $('div.plain').hide();
+
+  /**
+   * Add extra info (this is here so that only users with JavaScript
+   * enabled see it.)
+   */
+  $('span.nojavascript')
+    .removeClass('nojavascript')
+    .text('To switch between the interactive traceback and the plaintext ' +
+          'one, you can click on the "Traceback" headline.  From the text ' +
+          'traceback you can also create a paste of it.  For code execution ' +
+          'mouse-over the frame you want to debug and click on the console ' +
+          'icon on the right side.');
+
+  /**
+   * Add the pastebin feature
+   */
+  $('div.plain form')
+    .submit(function() {
+      $('input[@type="submit"]', this).val('submitting...');
+      $.ajax({
+        dataType:     'json',
+        url:          './__debugger__',
+        data:         {tb: TRACEBACK, cmd: 'paste'},
+        success:      function(data) {
+          console.log(data);
+          $('div.plain span.pastemessage')
+            .removeClass('pastemessage')
+            .text('Paste created: ')
+            .append($('<a>#' + data.id + '</a>').attr('href', data.url));
+      }});
+      return false;
+    });
+
+  // if we have javascript we submit by ajax anyways, so no need for the
+  // not scaling textarea.
+  var plainTraceback = $('div.plain textarea');
+  plainTraceback.replaceWith($('<pre>').text(plainTraceback.text()));
+});
+
+
+/**
+ * Helper function for shell initialization
+ */
+function openShell(consoleNode, target, frameID) {
+  if (consoleNode)
+    return consoleNode.slideToggle('fast');
+  consoleNode = $('<pre class="console">')
+    .appendTo(target.parent())
+    .hide()
+  var historyPos = 0, history = [''];
+  var output = $('<div class="output">[console ready]</div>')
+    .appendTo(consoleNode);
+  var form = $('<form>&gt;&gt;&gt; </form>')
+    .submit(function() {
+      var cmd = command.val();
+      $.get('./__debugger__', {cmd: cmd, frm: frameID}, function(data) {
+        var tmp = $('<div>').html(data);
+        $('span.extended', tmp).each(function() {
+          var hidden = $(this).wrap('<span>').hide();
+          hidden
+            .parent()
+            .append($('<a href="#" class="toggle">&nbsp;&nbsp;</a>')
+              .click(function() {
+                hidden.toggle();
+                $(this).toggleClass('open')
+                return false;
+              }));
+        });
+        output.append(tmp);
+        command.focus();
+        var old = history.pop();
+        history.push(cmd);
+        if (typeof old != 'undefined')
+          history.push(old);
+        historyPos = history.length - 1;
+      });
+      command.val('');
+      return false;
+    }).
+    appendTo(consoleNode);
+
+  var command = $('<input type="text">')
+    .appendTo(form)
+    .keypress(function(e) {
+      if (e.charCode == 100 && e.ctrlKey) {
+        output.text('--- screen cleared ---');
+        return false;
+      }
+      else if (e.charCode == 0 && (e.keyCode == 38 || e.keyCode == 40)) {
+        if (e.keyCode == 38 && historyPos > 0)
+          historyPos--;
+        else if (e.keyCode == 40 && historyPos < history.length)
+          historyPos++;
+        command.val(history[historyPos]);
+        return false;
+      }
+    });
+    
+  return consoleNode.slideDown('fast', function() {
+    command.focus();
+  });
+}
+
+/**
+ * Focus the current block in the source view.
+ */
+function focusSourceBlock() {
+  var tmp, line = $('table.source tr.current');
+  for (var i = 0; i < 7; i++) {
+    tmp = line.prev();
+    if (!(tmp && tmp.is('.in-frame')))
+      break
+    line = tmp;
+  }
+  var container = $('div.sourceview')[0];
+  container.scrollTop = line.offset().top - container.offsetTop;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/debug/shared/jquery.js	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,11 @@
+/*
+ * jQuery 1.2.3 - New Wave Javascript
+ *
+ * Copyright (c) 2008 John Resig (jquery.com)
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * $Date: 2008-02-06 00:21:25 -0500 (Wed, 06 Feb 2008) $
+ * $Rev: 4663 $
+ */
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(J(){7(1e.3N)L w=1e.3N;L E=1e.3N=J(a,b){K 1B E.2l.4T(a,b)};7(1e.$)L D=1e.$;1e.$=E;L u=/^[^<]*(<(.|\\s)+>)[^>]*$|^#(\\w+)$/;L G=/^.[^:#\\[\\.]*$/;E.1n=E.2l={4T:J(d,b){d=d||T;7(d.15){6[0]=d;6.M=1;K 6}N 7(1o d=="25"){L c=u.2O(d);7(c&&(c[1]||!b)){7(c[1])d=E.4a([c[1]],b);N{L a=T.5J(c[3]);7(a)7(a.2w!=c[3])K E().2s(d);N{6[0]=a;6.M=1;K 6}N d=[]}}N K 1B E(b).2s(d)}N 7(E.1q(d))K 1B E(T)[E.1n.21?"21":"3U"](d);K 6.6E(d.1k==1M&&d||(d.5h||d.M&&d!=1e&&!d.15&&d[0]!=10&&d[0].15)&&E.2I(d)||[d])},5h:"1.2.3",87:J(){K 6.M},M:0,22:J(a){K a==10?E.2I(6):6[a]},2F:J(b){L a=E(b);a.54=6;K a},6E:J(a){6.M=0;1M.2l.1g.1i(6,a);K 6},R:J(a,b){K E.R(6,a,b)},4X:J(b){L a=-1;6.R(J(i){7(6==b)a=i});K a},1J:J(c,a,b){L d=c;7(c.1k==4e)7(a==10)K 6.M&&E[b||"1J"](6[0],c)||10;N{d={};d[c]=a}K 6.R(J(i){Q(c 1p d)E.1J(b?6.W:6,c,E.1l(6,d[c],b,i,c))})},1j:J(b,a){7((b==\'27\'||b==\'1R\')&&2M(a)<0)a=10;K 6.1J(b,a,"2o")},1u:J(b){7(1o b!="3V"&&b!=V)K 6.4x().3t((6[0]&&6[0].2i||T).5r(b));L a="";E.R(b||6,J(){E.R(6.3p,J(){7(6.15!=8)a+=6.15!=1?6.6K:E.1n.1u([6])})});K a},5m:J(b){7(6[0])E(b,6[0].2i).5k().3o(6[0]).2c(J(){L a=6;2b(a.1C)a=a.1C;K a}).3t(6);K 6},8w:J(a){K 6.R(J(){E(6).6z().5m(a)})},8p:J(a){K 6.R(J(){E(6).5m(a)})},3t:J(){K 6.3O(18,P,S,J(a){7(6.15==1)6.38(a)})},6q:J(){K 6.3O(18,P,P,J(a){7(6.15==1)6.3o(a,6.1C)})},6o:J(){K 6.3O(18,S,S,J(a){6.1a.3o(a,6)})},5a:J(){K 6.3O(18,S,P,J(a){6.1a.3o(a,6.2B)})},3h:J(){K 6.54||E([])},2s:J(b){L c=E.2c(6,J(a){K E.2s(b,a)});K 6.2F(/[^+>] [^+>]/.17(b)||b.1f("..")>-1?E.57(c):c)},5k:J(e){L f=6.2c(J(){7(E.14.1d&&!E.3E(6)){L a=6.69(P),4Y=T.3s("1x");4Y.38(a);K E.4a([4Y.3d])[0]}N K 6.69(P)});L d=f.2s("*").4R().R(J(){7(6[F]!=10)6[F]=V});7(e===P)6.2s("*").4R().R(J(i){7(6.15==3)K;L c=E.O(6,"2R");Q(L a 1p c)Q(L b 1p c[a])E.16.1b(d[i],a,c[a][b],c[a][b].O)});K f},1E:J(b){K 6.2F(E.1q(b)&&E.3y(6,J(a,i){K b.1P(a,i)})||E.3e(b,6))},56:J(b){7(b.1k==4e)7(G.17(b))K 6.2F(E.3e(b,6,P));N b=E.3e(b,6);L a=b.M&&b[b.M-1]!==10&&!b.15;K 6.1E(J(){K a?E.33(6,b)<0:6!=b})},1b:J(a){K!a?6:6.2F(E.37(6.22(),a.1k==4e?E(a).22():a.M!=10&&(!a.12||E.12(a,"3u"))?a:[a]))},3H:J(a){K a?E.3e(a,6).M>0:S},7j:J(a){K 6.3H("."+a)},5O:J(b){7(b==10){7(6.M){L c=6[0];7(E.12(c,"2k")){L e=c.3T,5I=[],11=c.11,2X=c.U=="2k-2X";7(e<0)K V;Q(L i=2X?e:0,2f=2X?e+1:11.M;i<2f;i++){L d=11[i];7(d.2p){b=E.14.1d&&!d.9J.1A.9y?d.1u:d.1A;7(2X)K b;5I.1g(b)}}K 5I}N K(6[0].1A||"").1r(/\\r/g,"")}K 10}K 6.R(J(){7(6.15!=1)K;7(b.1k==1M&&/5u|5t/.17(6.U))6.3k=(E.33(6.1A,b)>=0||E.33(6.31,b)>=0);N 7(E.12(6,"2k")){L a=b.1k==1M?b:[b];E("98",6).R(J(){6.2p=(E.33(6.1A,a)>=0||E.33(6.1u,a)>=0)});7(!a.M)6.3T=-1}N 6.1A=b})},3q:J(a){K a==10?(6.M?6[0].3d:V):6.4x().3t(a)},6S:J(a){K 6.5a(a).1V()},6Z:J(i){K 6.2K(i,i+1)},2K:J(){K 6.2F(1M.2l.2K.1i(6,18))},2c:J(b){K 6.2F(E.2c(6,J(a,i){K b.1P(a,i,a)}))},4R:J(){K 6.1b(6.54)},O:J(d,b){L a=d.23(".");a[1]=a[1]?"."+a[1]:"";7(b==V){L c=6.5n("8P"+a[1]+"!",[a[0]]);7(c==10&&6.M)c=E.O(6[0],d);K c==V&&a[1]?6.O(a[0]):c}N K 6.1N("8K"+a[1]+"!",[a[0],b]).R(J(){E.O(6,d,b)})},35:J(a){K 6.R(J(){E.35(6,a)})},3O:J(g,f,h,d){L e=6.M>1,3n;K 6.R(J(){7(!3n){3n=E.4a(g,6.2i);7(h)3n.8D()}L b=6;7(f&&E.12(6,"1O")&&E.12(3n[0],"4v"))b=6.3S("1U")[0]||6.38(6.2i.3s("1U"));L c=E([]);E.R(3n,J(){L a=e?E(6).5k(P)[0]:6;7(E.12(a,"1m")){c=c.1b(a)}N{7(a.15==1)c=c.1b(E("1m",a).1V());d.1P(b,a)}});c.R(6A)})}};E.2l.4T.2l=E.2l;J 6A(i,a){7(a.3Q)E.3P({1c:a.3Q,3l:S,1H:"1m"});N E.5g(a.1u||a.6x||a.3d||"");7(a.1a)a.1a.34(a)}E.1s=E.1n.1s=J(){L b=18[0]||{},i=1,M=18.M,5c=S,11;7(b.1k==8d){5c=b;b=18[1]||{};i=2}7(1o b!="3V"&&1o b!="J")b={};7(M==1){b=6;i=0}Q(;i<M;i++)7((11=18[i])!=V)Q(L a 1p 11){7(b===11[a])6w;7(5c&&11[a]&&1o 11[a]=="3V"&&b[a]&&!11[a].15)b[a]=E.1s(b[a],11[a]);N 7(11[a]!=10)b[a]=11[a]}K b};L F="3N"+(1B 3v()).3L(),6t=0,5b={};L H=/z-?4X|86-?84|1w|6k|7Z-?1R/i;E.1s({7Y:J(a){1e.$=D;7(a)1e.3N=w;K E},1q:J(a){K!!a&&1o a!="25"&&!a.12&&a.1k!=1M&&/J/i.17(a+"")},3E:J(a){K a.1F&&!a.1h||a.28&&a.2i&&!a.2i.1h},5g:J(a){a=E.3g(a);7(a){L b=T.3S("6f")[0]||T.1F,1m=T.3s("1m");1m.U="1u/4m";7(E.14.1d)1m.1u=a;N 1m.38(T.5r(a));b.38(1m);b.34(1m)}},12:J(b,a){K b.12&&b.12.2E()==a.2E()},1T:{},O:J(c,d,b){c=c==1e?5b:c;L a=c[F];7(!a)a=c[F]=++6t;7(d&&!E.1T[a])E.1T[a]={};7(b!=10)E.1T[a][d]=b;K d?E.1T[a][d]:a},35:J(c,b){c=c==1e?5b:c;L a=c[F];7(b){7(E.1T[a]){2V E.1T[a][b];b="";Q(b 1p E.1T[a])1Q;7(!b)E.35(c)}}N{1S{2V c[F]}1X(e){7(c.52)c.52(F)}2V E.1T[a]}},R:J(c,a,b){7(b){7(c.M==10){Q(L d 1p c)7(a.1i(c[d],b)===S)1Q}N Q(L i=0,M=c.M;i<M;i++)7(a.1i(c[i],b)===S)1Q}N{7(c.M==10){Q(L d 1p c)7(a.1P(c[d],d,c[d])===S)1Q}N Q(L i=0,M=c.M,1A=c[0];i<M&&a.1P(1A,i,1A)!==S;1A=c[++i]){}}K c},1l:J(b,a,c,i,d){7(E.1q(a))a=a.1P(b,i);K a&&a.1k==51&&c=="2o"&&!H.17(d)?a+"2S":a},1t:{1b:J(c,b){E.R((b||"").23(/\\s+/),J(i,a){7(c.15==1&&!E.1t.3Y(c.1t,a))c.1t+=(c.1t?" ":"")+a})},1V:J(c,b){7(c.15==1)c.1t=b!=10?E.3y(c.1t.23(/\\s+/),J(a){K!E.1t.3Y(b,a)}).6a(" "):""},3Y:J(b,a){K E.33(a,(b.1t||b).3X().23(/\\s+/))>-1}},68:J(b,c,a){L e={};Q(L d 1p c){e[d]=b.W[d];b.W[d]=c[d]}a.1P(b);Q(L d 1p c)b.W[d]=e[d]},1j:J(d,e,c){7(e=="27"||e=="1R"){L b,46={43:"4W",4U:"1Z",19:"3D"},3c=e=="27"?["7O","7M"]:["7J","7I"];J 5E(){b=e=="27"?d.7H:d.7F;L a=0,2N=0;E.R(3c,J(){a+=2M(E.2o(d,"7E"+6,P))||0;2N+=2M(E.2o(d,"2N"+6+"5X",P))||0});b-=24.7C(a+2N)}7(E(d).3H(":4d"))5E();N E.68(d,46,5E);K 24.2f(0,b)}K E.2o(d,e,c)},2o:J(e,k,j){L d;J 3x(b){7(!E.14.2d)K S;L a=T.4c.4K(b,V);K!a||a.4M("3x")==""}7(k=="1w"&&E.14.1d){d=E.1J(e.W,"1w");K d==""?"1":d}7(E.14.2z&&k=="19"){L c=e.W.50;e.W.50="0 7r 7o";e.W.50=c}7(k.1D(/4g/i))k=y;7(!j&&e.W&&e.W[k])d=e.W[k];N 7(T.4c&&T.4c.4K){7(k.1D(/4g/i))k="4g";k=k.1r(/([A-Z])/g,"-$1").2h();L h=T.4c.4K(e,V);7(h&&!3x(e))d=h.4M(k);N{L f=[],2C=[];Q(L a=e;a&&3x(a);a=a.1a)2C.4J(a);Q(L i=0;i<2C.M;i++)7(3x(2C[i])){f[i]=2C[i].W.19;2C[i].W.19="3D"}d=k=="19"&&f[2C.M-1]!=V?"2H":(h&&h.4M(k))||"";Q(L i=0;i<f.M;i++)7(f[i]!=V)2C[i].W.19=f[i]}7(k=="1w"&&d=="")d="1"}N 7(e.4n){L g=k.1r(/\\-(\\w)/g,J(a,b){K b.2E()});d=e.4n[k]||e.4n[g];7(!/^\\d+(2S)?$/i.17(d)&&/^\\d/.17(d)){L l=e.W.26,3K=e.3K.26;e.3K.26=e.4n.26;e.W.26=d||0;d=e.W.7f+"2S";e.W.26=l;e.3K.26=3K}}K d},4a:J(l,h){L k=[];h=h||T;7(1o h.3s==\'10\')h=h.2i||h[0]&&h[0].2i||T;E.R(l,J(i,d){7(!d)K;7(d.1k==51)d=d.3X();7(1o d=="25"){d=d.1r(/(<(\\w+)[^>]*?)\\/>/g,J(b,a,c){K c.1D(/^(aa|a6|7e|a5|4D|7a|a0|3m|9W|9U|9S)$/i)?b:a+"></"+c+">"});L f=E.3g(d).2h(),1x=h.3s("1x");L e=!f.1f("<9P")&&[1,"<2k 74=\'74\'>","</2k>"]||!f.1f("<9M")&&[1,"<73>","</73>"]||f.1D(/^<(9G|1U|9E|9B|9x)/)&&[1,"<1O>","</1O>"]||!f.1f("<4v")&&[2,"<1O><1U>","</1U></1O>"]||(!f.1f("<9w")||!f.1f("<9v"))&&[3,"<1O><1U><4v>","</4v></1U></1O>"]||!f.1f("<7e")&&[2,"<1O><1U></1U><6V>","</6V></1O>"]||E.14.1d&&[1,"1x<1x>","</1x>"]||[0,"",""];1x.3d=e[1]+d+e[2];2b(e[0]--)1x=1x.5o;7(E.14.1d){L g=!f.1f("<1O")&&f.1f("<1U")<0?1x.1C&&1x.1C.3p:e[1]=="<1O>"&&f.1f("<1U")<0?1x.3p:[];Q(L j=g.M-1;j>=0;--j)7(E.12(g[j],"1U")&&!g[j].3p.M)g[j].1a.34(g[j]);7(/^\\s/.17(d))1x.3o(h.5r(d.1D(/^\\s*/)[0]),1x.1C)}d=E.2I(1x.3p)}7(d.M===0&&(!E.12(d,"3u")&&!E.12(d,"2k")))K;7(d[0]==10||E.12(d,"3u")||d.11)k.1g(d);N k=E.37(k,d)});K k},1J:J(d,e,c){7(!d||d.15==3||d.15==8)K 10;L f=E.3E(d)?{}:E.46;7(e=="2p"&&E.14.2d)d.1a.3T;7(f[e]){7(c!=10)d[f[e]]=c;K d[f[e]]}N 7(E.14.1d&&e=="W")K E.1J(d.W,"9u",c);N 7(c==10&&E.14.1d&&E.12(d,"3u")&&(e=="9r"||e=="9o"))K d.9m(e).6K;N 7(d.28){7(c!=10){7(e=="U"&&E.12(d,"4D")&&d.1a)6Q"U 9i 9h\'t 9g 9e";d.9b(e,""+c)}7(E.14.1d&&/6O|3Q/.17(e)&&!E.3E(d))K d.4z(e,2);K d.4z(e)}N{7(e=="1w"&&E.14.1d){7(c!=10){d.6k=1;d.1E=(d.1E||"").1r(/6M\\([^)]*\\)/,"")+(2M(c).3X()=="96"?"":"6M(1w="+c*6L+")")}K d.1E&&d.1E.1f("1w=")>=0?(2M(d.1E.1D(/1w=([^)]*)/)[1])/6L).3X():""}e=e.1r(/-([a-z])/95,J(a,b){K b.2E()});7(c!=10)d[e]=c;K d[e]}},3g:J(a){K(a||"").1r(/^\\s+|\\s+$/g,"")},2I:J(b){L a=[];7(1o b!="93")Q(L i=0,M=b.M;i<M;i++)a.1g(b[i]);N a=b.2K(0);K a},33:J(b,a){Q(L i=0,M=a.M;i<M;i++)7(a[i]==b)K i;K-1},37:J(a,b){7(E.14.1d){Q(L i=0;b[i];i++)7(b[i].15!=8)a.1g(b[i])}N Q(L i=0;b[i];i++)a.1g(b[i]);K a},57:J(a){L c=[],2r={};1S{Q(L i=0,M=a.M;i<M;i++){L b=E.O(a[i]);7(!2r[b]){2r[b]=P;c.1g(a[i])}}}1X(e){c=a}K c},3y:J(c,a,d){L b=[];Q(L i=0,M=c.M;i<M;i++)7(!d&&a(c[i],i)||d&&!a(c[i],i))b.1g(c[i]);K b},2c:J(d,a){L c=[];Q(L i=0,M=d.M;i<M;i++){L b=a(d[i],i);7(b!==V&&b!=10){7(b.1k!=1M)b=[b];c=c.71(b)}}K c}});L v=8Y.8W.2h();E.14={5K:(v.1D(/.+(?:8T|8S|8R|8O)[\\/: ]([\\d.]+)/)||[])[1],2d:/77/.17(v),2z:/2z/.17(v),1d:/1d/.17(v)&&!/2z/.17(v),48:/48/.17(v)&&!/(8L|77)/.17(v)};L y=E.14.1d?"6H":"75";E.1s({8I:!E.14.1d||T.6F=="79",46:{"Q":"8F","8E":"1t","4g":y,75:y,6H:y,3d:"3d",1t:"1t",1A:"1A",2Y:"2Y",3k:"3k",8C:"8B",2p:"2p",8A:"8z",3T:"3T",6C:"6C",28:"28",12:"12"}});E.R({6B:J(a){K a.1a},8y:J(a){K E.4u(a,"1a")},8x:J(a){K E.2Z(a,2,"2B")},8v:J(a){K E.2Z(a,2,"4t")},8u:J(a){K E.4u(a,"2B")},8t:J(a){K E.4u(a,"4t")},8s:J(a){K E.5i(a.1a.1C,a)},8r:J(a){K E.5i(a.1C)},6z:J(a){K E.12(a,"8q")?a.8o||a.8n.T:E.2I(a.3p)}},J(c,d){E.1n[c]=J(b){L a=E.2c(6,d);7(b&&1o b=="25")a=E.3e(b,a);K 6.2F(E.57(a))}});E.R({6y:"3t",8m:"6q",3o:"6o",8l:"5a",8k:"6S"},J(c,b){E.1n[c]=J(){L a=18;K 6.R(J(){Q(L i=0,M=a.M;i<M;i++)E(a[i])[b](6)})}});E.R({8j:J(a){E.1J(6,a,"");7(6.15==1)6.52(a)},8i:J(a){E.1t.1b(6,a)},8h:J(a){E.1t.1V(6,a)},8g:J(a){E.1t[E.1t.3Y(6,a)?"1V":"1b"](6,a)},1V:J(a){7(!a||E.1E(a,[6]).r.M){E("*",6).1b(6).R(J(){E.16.1V(6);E.35(6)});7(6.1a)6.1a.34(6)}},4x:J(){E(">*",6).1V();2b(6.1C)6.34(6.1C)}},J(a,b){E.1n[a]=J(){K 6.R(b,18)}});E.R(["8f","5X"],J(i,c){L b=c.2h();E.1n[b]=J(a){K 6[0]==1e?E.14.2z&&T.1h["5e"+c]||E.14.2d&&1e["8e"+c]||T.6F=="79"&&T.1F["5e"+c]||T.1h["5e"+c]:6[0]==T?24.2f(24.2f(T.1h["5d"+c],T.1F["5d"+c]),24.2f(T.1h["5L"+c],T.1F["5L"+c])):a==10?(6.M?E.1j(6[0],b):V):6.1j(b,a.1k==4e?a:a+"2S")}});L C=E.14.2d&&4s(E.14.5K)<8c?"(?:[\\\\w*4r-]|\\\\\\\\.)":"(?:[\\\\w\\8b-\\8a*4r-]|\\\\\\\\.)",6v=1B 4q("^>\\\\s*("+C+"+)"),6u=1B 4q("^("+C+"+)(#)("+C+"+)"),6s=1B 4q("^([#.]?)("+C+"*)");E.1s({6r:{"":J(a,i,m){K m[2]=="*"||E.12(a,m[2])},"#":J(a,i,m){K a.4z("2w")==m[2]},":":{89:J(a,i,m){K i<m[3]-0},88:J(a,i,m){K i>m[3]-0},2Z:J(a,i,m){K m[3]-0==i},6Z:J(a,i,m){K m[3]-0==i},3j:J(a,i){K i==0},3J:J(a,i,m,r){K i==r.M-1},6n:J(a,i){K i%2==0},6l:J(a,i){K i%2},"3j-4p":J(a){K a.1a.3S("*")[0]==a},"3J-4p":J(a){K E.2Z(a.1a.5o,1,"4t")==a},"83-4p":J(a){K!E.2Z(a.1a.5o,2,"4t")},6B:J(a){K a.1C},4x:J(a){K!a.1C},82:J(a,i,m){K(a.6x||a.81||E(a).1u()||"").1f(m[3])>=0},4d:J(a){K"1Z"!=a.U&&E.1j(a,"19")!="2H"&&E.1j(a,"4U")!="1Z"},1Z:J(a){K"1Z"==a.U||E.1j(a,"19")=="2H"||E.1j(a,"4U")=="1Z"},80:J(a){K!a.2Y},2Y:J(a){K a.2Y},3k:J(a){K a.3k},2p:J(a){K a.2p||E.1J(a,"2p")},1u:J(a){K"1u"==a.U},5u:J(a){K"5u"==a.U},5t:J(a){K"5t"==a.U},59:J(a){K"59"==a.U},3I:J(a){K"3I"==a.U},58:J(a){K"58"==a.U},6j:J(a){K"6j"==a.U},6i:J(a){K"6i"==a.U},2G:J(a){K"2G"==a.U||E.12(a,"2G")},4D:J(a){K/4D|2k|6h|2G/i.17(a.12)},3Y:J(a,i,m){K E.2s(m[3],a).M},7X:J(a){K/h\\d/i.17(a.12)},7W:J(a){K E.3y(E.3G,J(b){K a==b.Y}).M}}},6g:[/^(\\[) *@?([\\w-]+) *([!*$^~=]*) *(\'?"?)(.*?)\\4 *\\]/,/^(:)([\\w-]+)\\("?\'?(.*?(\\(.*?\\))?[^(]*?)"?\'?\\)/,1B 4q("^([:.#]*)("+C+"+)")],3e:J(a,c,b){L d,2m=[];2b(a&&a!=d){d=a;L f=E.1E(a,c,b);a=f.t.1r(/^\\s*,\\s*/,"");2m=b?c=f.r:E.37(2m,f.r)}K 2m},2s:J(t,p){7(1o t!="25")K[t];7(p&&p.15!=1&&p.15!=9)K[];p=p||T;L d=[p],2r=[],3J,12;2b(t&&3J!=t){L r=[];3J=t;t=E.3g(t);L o=S;L g=6v;L m=g.2O(t);7(m){12=m[1].2E();Q(L i=0;d[i];i++)Q(L c=d[i].1C;c;c=c.2B)7(c.15==1&&(12=="*"||c.12.2E()==12))r.1g(c);d=r;t=t.1r(g,"");7(t.1f(" ")==0)6w;o=P}N{g=/^([>+~])\\s*(\\w*)/i;7((m=g.2O(t))!=V){r=[];L l={};12=m[2].2E();m=m[1];Q(L j=0,3f=d.M;j<3f;j++){L n=m=="~"||m=="+"?d[j].2B:d[j].1C;Q(;n;n=n.2B)7(n.15==1){L h=E.O(n);7(m=="~"&&l[h])1Q;7(!12||n.12.2E()==12){7(m=="~")l[h]=P;r.1g(n)}7(m=="+")1Q}}d=r;t=E.3g(t.1r(g,""));o=P}}7(t&&!o){7(!t.1f(",")){7(p==d[0])d.4l();2r=E.37(2r,d);r=d=[p];t=" "+t.6e(1,t.M)}N{L k=6u;L m=k.2O(t);7(m){m=[0,m[2],m[3],m[1]]}N{k=6s;m=k.2O(t)}m[2]=m[2].1r(/\\\\/g,"");L f=d[d.M-1];7(m[1]=="#"&&f&&f.5J&&!E.3E(f)){L q=f.5J(m[2]);7((E.14.1d||E.14.2z)&&q&&1o q.2w=="25"&&q.2w!=m[2])q=E(\'[@2w="\'+m[2]+\'"]\',f)[0];d=r=q&&(!m[3]||E.12(q,m[3]))?[q]:[]}N{Q(L i=0;d[i];i++){L a=m[1]=="#"&&m[3]?m[3]:m[1]!=""||m[0]==""?"*":m[2];7(a=="*"&&d[i].12.2h()=="3V")a="3m";r=E.37(r,d[i].3S(a))}7(m[1]==".")r=E.55(r,m[2]);7(m[1]=="#"){L e=[];Q(L i=0;r[i];i++)7(r[i].4z("2w")==m[2]){e=[r[i]];1Q}r=e}d=r}t=t.1r(k,"")}}7(t){L b=E.1E(t,r);d=r=b.r;t=E.3g(b.t)}}7(t)d=[];7(d&&p==d[0])d.4l();2r=E.37(2r,d);K 2r},55:J(r,m,a){m=" "+m+" ";L c=[];Q(L i=0;r[i];i++){L b=(" "+r[i].1t+" ").1f(m)>=0;7(!a&&b||a&&!b)c.1g(r[i])}K c},1E:J(t,r,h){L d;2b(t&&t!=d){d=t;L p=E.6g,m;Q(L i=0;p[i];i++){m=p[i].2O(t);7(m){t=t.7V(m[0].M);m[2]=m[2].1r(/\\\\/g,"");1Q}}7(!m)1Q;7(m[1]==":"&&m[2]=="56")r=G.17(m[3])?E.1E(m[3],r,P).r:E(r).56(m[3]);N 7(m[1]==".")r=E.55(r,m[2],h);N 7(m[1]=="["){L g=[],U=m[3];Q(L i=0,3f=r.M;i<3f;i++){L a=r[i],z=a[E.46[m[2]]||m[2]];7(z==V||/6O|3Q|2p/.17(m[2]))z=E.1J(a,m[2])||\'\';7((U==""&&!!z||U=="="&&z==m[5]||U=="!="&&z!=m[5]||U=="^="&&z&&!z.1f(m[5])||U=="$="&&z.6e(z.M-m[5].M)==m[5]||(U=="*="||U=="~=")&&z.1f(m[5])>=0)^h)g.1g(a)}r=g}N 7(m[1]==":"&&m[2]=="2Z-4p"){L e={},g=[],17=/(-?)(\\d*)n((?:\\+|-)?\\d*)/.2O(m[3]=="6n"&&"2n"||m[3]=="6l"&&"2n+1"||!/\\D/.17(m[3])&&"7U+"+m[3]||m[3]),3j=(17[1]+(17[2]||1))-0,d=17[3]-0;Q(L i=0,3f=r.M;i<3f;i++){L j=r[i],1a=j.1a,2w=E.O(1a);7(!e[2w]){L c=1;Q(L n=1a.1C;n;n=n.2B)7(n.15==1)n.4k=c++;e[2w]=P}L b=S;7(3j==0){7(j.4k==d)b=P}N 7((j.4k-d)%3j==0&&(j.4k-d)/3j>=0)b=P;7(b^h)g.1g(j)}r=g}N{L f=E.6r[m[1]];7(1o f=="3V")f=f[m[2]];7(1o f=="25")f=6c("S||J(a,i){K "+f+";}");r=E.3y(r,J(a,i){K f(a,i,m,r)},h)}}K{r:r,t:t}},4u:J(b,c){L d=[];L a=b[c];2b(a&&a!=T){7(a.15==1)d.1g(a);a=a[c]}K d},2Z:J(a,e,c,b){e=e||1;L d=0;Q(;a;a=a[c])7(a.15==1&&++d==e)1Q;K a},5i:J(n,a){L r=[];Q(;n;n=n.2B){7(n.15==1&&(!a||n!=a))r.1g(n)}K r}});E.16={1b:J(f,i,g,e){7(f.15==3||f.15==8)K;7(E.14.1d&&f.53!=10)f=1e;7(!g.2D)g.2D=6.2D++;7(e!=10){L h=g;g=J(){K h.1i(6,18)};g.O=e;g.2D=h.2D}L j=E.O(f,"2R")||E.O(f,"2R",{}),1v=E.O(f,"1v")||E.O(f,"1v",J(){L a;7(1o E=="10"||E.16.5f)K a;a=E.16.1v.1i(18.3R.Y,18);K a});1v.Y=f;E.R(i.23(/\\s+/),J(c,b){L a=b.23(".");b=a[0];g.U=a[1];L d=j[b];7(!d){d=j[b]={};7(!E.16.2y[b]||E.16.2y[b].4j.1P(f)===S){7(f.3F)f.3F(b,1v,S);N 7(f.6b)f.6b("4i"+b,1v)}}d[g.2D]=g;E.16.2a[b]=P});f=V},2D:1,2a:{},1V:J(e,h,f){7(e.15==3||e.15==8)K;L i=E.O(e,"2R"),29,4X;7(i){7(h==10||(1o h=="25"&&h.7T(0)=="."))Q(L g 1p i)6.1V(e,g+(h||""));N{7(h.U){f=h.2q;h=h.U}E.R(h.23(/\\s+/),J(b,a){L c=a.23(".");a=c[0];7(i[a]){7(f)2V i[a][f.2D];N Q(f 1p i[a])7(!c[1]||i[a][f].U==c[1])2V i[a][f];Q(29 1p i[a])1Q;7(!29){7(!E.16.2y[a]||E.16.2y[a].4h.1P(e)===S){7(e.67)e.67(a,E.O(e,"1v"),S);N 7(e.66)e.66("4i"+a,E.O(e,"1v"))}29=V;2V i[a]}}})}Q(29 1p i)1Q;7(!29){L d=E.O(e,"1v");7(d)d.Y=V;E.35(e,"2R");E.35(e,"1v")}}},1N:J(g,c,d,f,h){c=E.2I(c||[]);7(g.1f("!")>=0){g=g.2K(0,-1);L a=P}7(!d){7(6.2a[g])E("*").1b([1e,T]).1N(g,c)}N{7(d.15==3||d.15==8)K 10;L b,29,1n=E.1q(d[g]||V),16=!c[0]||!c[0].36;7(16)c.4J(6.4Z({U:g,2L:d}));c[0].U=g;7(a)c[0].65=P;7(E.1q(E.O(d,"1v")))b=E.O(d,"1v").1i(d,c);7(!1n&&d["4i"+g]&&d["4i"+g].1i(d,c)===S)b=S;7(16)c.4l();7(h&&E.1q(h)){29=h.1i(d,b==V?c:c.71(b));7(29!==10)b=29}7(1n&&f!==S&&b!==S&&!(E.12(d,\'a\')&&g=="4V")){6.5f=P;1S{d[g]()}1X(e){}}6.5f=S}K b},1v:J(c){L a;c=E.16.4Z(c||1e.16||{});L b=c.U.23(".");c.U=b[0];L f=E.O(6,"2R")&&E.O(6,"2R")[c.U],42=1M.2l.2K.1P(18,1);42.4J(c);Q(L j 1p f){L d=f[j];42[0].2q=d;42[0].O=d.O;7(!b[1]&&!c.65||d.U==b[1]){L e=d.1i(6,42);7(a!==S)a=e;7(e===S){c.36();c.44()}}}7(E.14.1d)c.2L=c.36=c.44=c.2q=c.O=V;K a},4Z:J(c){L a=c;c=E.1s({},a);c.36=J(){7(a.36)a.36();a.7S=S};c.44=J(){7(a.44)a.44();a.7R=P};7(!c.2L)c.2L=c.7Q||T;7(c.2L.15==3)c.2L=a.2L.1a;7(!c.4S&&c.5w)c.4S=c.5w==c.2L?c.7P:c.5w;7(c.64==V&&c.63!=V){L b=T.1F,1h=T.1h;c.64=c.63+(b&&b.2v||1h&&1h.2v||0)-(b.62||0);c.7N=c.7L+(b&&b.2x||1h&&1h.2x||0)-(b.60||0)}7(!c.3c&&((c.4f||c.4f===0)?c.4f:c.5Z))c.3c=c.4f||c.5Z;7(!c.7b&&c.5Y)c.7b=c.5Y;7(!c.3c&&c.2G)c.3c=(c.2G&1?1:(c.2G&2?3:(c.2G&4?2:0)));K c},2y:{21:{4j:J(){5M();K},4h:J(){K}},3C:{4j:J(){7(E.14.1d)K S;E(6).2j("4P",E.16.2y.3C.2q);K P},4h:J(){7(E.14.1d)K S;E(6).3w("4P",E.16.2y.3C.2q);K P},2q:J(a){7(I(a,6))K P;18[0].U="3C";K E.16.1v.1i(6,18)}},3B:{4j:J(){7(E.14.1d)K S;E(6).2j("4O",E.16.2y.3B.2q);K P},4h:J(){7(E.14.1d)K S;E(6).3w("4O",E.16.2y.3B.2q);K P},2q:J(a){7(I(a,6))K P;18[0].U="3B";K E.16.1v.1i(6,18)}}}};E.1n.1s({2j:J(c,a,b){K c=="4H"?6.2X(c,a,b):6.R(J(){E.16.1b(6,c,b||a,b&&a)})},2X:J(d,b,c){K 6.R(J(){E.16.1b(6,d,J(a){E(6).3w(a);K(c||b).1i(6,18)},c&&b)})},3w:J(a,b){K 6.R(J(){E.16.1V(6,a,b)})},1N:J(c,a,b){K 6.R(J(){E.16.1N(c,a,6,P,b)})},5n:J(c,a,b){7(6[0])K E.16.1N(c,a,6[0],S,b);K 10},2g:J(){L b=18;K 6.4V(J(a){6.4N=0==6.4N?1:0;a.36();K b[6.4N].1i(6,18)||S})},7D:J(a,b){K 6.2j(\'3C\',a).2j(\'3B\',b)},21:J(a){5M();7(E.2Q)a.1P(T,E);N E.3A.1g(J(){K a.1P(6,E)});K 6}});E.1s({2Q:S,3A:[],21:J(){7(!E.2Q){E.2Q=P;7(E.3A){E.R(E.3A,J(){6.1i(T)});E.3A=V}E(T).5n("21")}}});L x=S;J 5M(){7(x)K;x=P;7(T.3F&&!E.14.2z)T.3F("5W",E.21,S);7(E.14.1d&&1e==3b)(J(){7(E.2Q)K;1S{T.1F.7B("26")}1X(3a){3z(18.3R,0);K}E.21()})();7(E.14.2z)T.3F("5W",J(){7(E.2Q)K;Q(L i=0;i<T.4L.M;i++)7(T.4L[i].2Y){3z(18.3R,0);K}E.21()},S);7(E.14.2d){L a;(J(){7(E.2Q)K;7(T.39!="5V"&&T.39!="1y"){3z(18.3R,0);K}7(a===10)a=E("W, 7a[7A=7z]").M;7(T.4L.M!=a){3z(18.3R,0);K}E.21()})()}E.16.1b(1e,"3U",E.21)}E.R(("7y,7x,3U,7w,5d,4H,4V,7v,"+"7G,7u,7t,4P,4O,7s,2k,"+"58,7K,7q,7p,3a").23(","),J(i,b){E.1n[b]=J(a){K a?6.2j(b,a):6.1N(b)}});L I=J(a,c){L b=a.4S;2b(b&&b!=c)1S{b=b.1a}1X(3a){b=c}K b==c};E(1e).2j("4H",J(){E("*").1b(T).3w()});E.1n.1s({3U:J(g,d,c){7(E.1q(g))K 6.2j("3U",g);L e=g.1f(" ");7(e>=0){L i=g.2K(e,g.M);g=g.2K(0,e)}c=c||J(){};L f="4Q";7(d)7(E.1q(d)){c=d;d=V}N{d=E.3m(d);f="61"}L h=6;E.3P({1c:g,U:f,1H:"3q",O:d,1y:J(a,b){7(b=="1W"||b=="5U")h.3q(i?E("<1x/>").3t(a.4b.1r(/<1m(.|\\s)*?\\/1m>/g,"")).2s(i):a.4b);h.R(c,[a.4b,b,a])}});K 6},7n:J(){K E.3m(6.5T())},5T:J(){K 6.2c(J(){K E.12(6,"3u")?E.2I(6.7m):6}).1E(J(){K 6.31&&!6.2Y&&(6.3k||/2k|6h/i.17(6.12)||/1u|1Z|3I/i.17(6.U))}).2c(J(i,c){L b=E(6).5O();K b==V?V:b.1k==1M?E.2c(b,J(a,i){K{31:c.31,1A:a}}):{31:c.31,1A:b}}).22()}});E.R("5S,6d,5R,6D,5Q,6m".23(","),J(i,o){E.1n[o]=J(f){K 6.2j(o,f)}});L B=(1B 3v).3L();E.1s({22:J(d,b,a,c){7(E.1q(b)){a=b;b=V}K E.3P({U:"4Q",1c:d,O:b,1W:a,1H:c})},7l:J(b,a){K E.22(b,V,a,"1m")},7k:J(c,b,a){K E.22(c,b,a,"3i")},7i:J(d,b,a,c){7(E.1q(b)){a=b;b={}}K E.3P({U:"61",1c:d,O:b,1W:a,1H:c})},85:J(a){E.1s(E.4I,a)},4I:{2a:P,U:"4Q",2U:0,5P:"4o/x-7h-3u-7g",5N:P,3l:P,O:V,6p:V,3I:V,49:{3M:"4o/3M, 1u/3M",3q:"1u/3q",1m:"1u/4m, 4o/4m",3i:"4o/3i, 1u/4m",1u:"1u/a7",4G:"*/*"}},4F:{},3P:J(s){L f,2W=/=\\?(&|$)/g,1z,O;s=E.1s(P,s,E.1s(P,{},E.4I,s));7(s.O&&s.5N&&1o s.O!="25")s.O=E.3m(s.O);7(s.1H=="4E"){7(s.U.2h()=="22"){7(!s.1c.1D(2W))s.1c+=(s.1c.1D(/\\?/)?"&":"?")+(s.4E||"7d")+"=?"}N 7(!s.O||!s.O.1D(2W))s.O=(s.O?s.O+"&":"")+(s.4E||"7d")+"=?";s.1H="3i"}7(s.1H=="3i"&&(s.O&&s.O.1D(2W)||s.1c.1D(2W))){f="4E"+B++;7(s.O)s.O=(s.O+"").1r(2W,"="+f+"$1");s.1c=s.1c.1r(2W,"="+f+"$1");s.1H="1m";1e[f]=J(a){O=a;1W();1y();1e[f]=10;1S{2V 1e[f]}1X(e){}7(h)h.34(g)}}7(s.1H=="1m"&&s.1T==V)s.1T=S;7(s.1T===S&&s.U.2h()=="22"){L i=(1B 3v()).3L();L j=s.1c.1r(/(\\?|&)4r=.*?(&|$)/,"$a4="+i+"$2");s.1c=j+((j==s.1c)?(s.1c.1D(/\\?/)?"&":"?")+"4r="+i:"")}7(s.O&&s.U.2h()=="22"){s.1c+=(s.1c.1D(/\\?/)?"&":"?")+s.O;s.O=V}7(s.2a&&!E.5H++)E.16.1N("5S");7((!s.1c.1f("a3")||!s.1c.1f("//"))&&s.1H=="1m"&&s.U.2h()=="22"){L h=T.3S("6f")[0];L g=T.3s("1m");g.3Q=s.1c;7(s.7c)g.a2=s.7c;7(!f){L l=S;g.9Z=g.9Y=J(){7(!l&&(!6.39||6.39=="5V"||6.39=="1y")){l=P;1W();1y();h.34(g)}}}h.38(g);K 10}L m=S;L k=1e.78?1B 78("9X.9V"):1B 76();k.9T(s.U,s.1c,s.3l,s.6p,s.3I);1S{7(s.O)k.4C("9R-9Q",s.5P);7(s.5C)k.4C("9O-5A-9N",E.4F[s.1c]||"9L, 9K 9I 9H 5z:5z:5z 9F");k.4C("X-9C-9A","76");k.4C("9z",s.1H&&s.49[s.1H]?s.49[s.1H]+", */*":s.49.4G)}1X(e){}7(s.6Y)s.6Y(k);7(s.2a)E.16.1N("6m",[k,s]);L c=J(a){7(!m&&k&&(k.39==4||a=="2U")){m=P;7(d){6I(d);d=V}1z=a=="2U"&&"2U"||!E.6X(k)&&"3a"||s.5C&&E.6J(k,s.1c)&&"5U"||"1W";7(1z=="1W"){1S{O=E.6W(k,s.1H)}1X(e){1z="5x"}}7(1z=="1W"){L b;1S{b=k.5q("6U-5A")}1X(e){}7(s.5C&&b)E.4F[s.1c]=b;7(!f)1W()}N E.5v(s,k,1z);1y();7(s.3l)k=V}};7(s.3l){L d=53(c,13);7(s.2U>0)3z(J(){7(k){k.9t();7(!m)c("2U")}},s.2U)}1S{k.9s(s.O)}1X(e){E.5v(s,k,V,e)}7(!s.3l)c();J 1W(){7(s.1W)s.1W(O,1z);7(s.2a)E.16.1N("5Q",[k,s])}J 1y(){7(s.1y)s.1y(k,1z);7(s.2a)E.16.1N("5R",[k,s]);7(s.2a&&!--E.5H)E.16.1N("6d")}K k},5v:J(s,a,b,e){7(s.3a)s.3a(a,b,e);7(s.2a)E.16.1N("6D",[a,s,e])},5H:0,6X:J(r){1S{K!r.1z&&9q.9p=="59:"||(r.1z>=6T&&r.1z<9n)||r.1z==6R||r.1z==9l||E.14.2d&&r.1z==10}1X(e){}K S},6J:J(a,c){1S{L b=a.5q("6U-5A");K a.1z==6R||b==E.4F[c]||E.14.2d&&a.1z==10}1X(e){}K S},6W:J(r,b){L c=r.5q("9k-U");L d=b=="3M"||!b&&c&&c.1f("3M")>=0;L a=d?r.9j:r.4b;7(d&&a.1F.28=="5x")6Q"5x";7(b=="1m")E.5g(a);7(b=="3i")a=6c("("+a+")");K a},3m:J(a){L s=[];7(a.1k==1M||a.5h)E.R(a,J(){s.1g(3r(6.31)+"="+3r(6.1A))});N Q(L j 1p a)7(a[j]&&a[j].1k==1M)E.R(a[j],J(){s.1g(3r(j)+"="+3r(6))});N s.1g(3r(j)+"="+3r(a[j]));K s.6a("&").1r(/%20/g,"+")}});E.1n.1s({1G:J(c,b){K c?6.2e({1R:"1G",27:"1G",1w:"1G"},c,b):6.1E(":1Z").R(J(){6.W.19=6.5s||"";7(E.1j(6,"19")=="2H"){L a=E("<"+6.28+" />").6y("1h");6.W.19=a.1j("19");7(6.W.19=="2H")6.W.19="3D";a.1V()}}).3h()},1I:J(b,a){K b?6.2e({1R:"1I",27:"1I",1w:"1I"},b,a):6.1E(":4d").R(J(){6.5s=6.5s||E.1j(6,"19");6.W.19="2H"}).3h()},6N:E.1n.2g,2g:J(a,b){K E.1q(a)&&E.1q(b)?6.6N(a,b):a?6.2e({1R:"2g",27:"2g",1w:"2g"},a,b):6.R(J(){E(6)[E(6).3H(":1Z")?"1G":"1I"]()})},9f:J(b,a){K 6.2e({1R:"1G"},b,a)},9d:J(b,a){K 6.2e({1R:"1I"},b,a)},9c:J(b,a){K 6.2e({1R:"2g"},b,a)},9a:J(b,a){K 6.2e({1w:"1G"},b,a)},99:J(b,a){K 6.2e({1w:"1I"},b,a)},97:J(c,a,b){K 6.2e({1w:a},c,b)},2e:J(l,k,j,h){L i=E.6P(k,j,h);K 6[i.2P===S?"R":"2P"](J(){7(6.15!=1)K S;L g=E.1s({},i);L f=E(6).3H(":1Z"),4A=6;Q(L p 1p l){7(l[p]=="1I"&&f||l[p]=="1G"&&!f)K E.1q(g.1y)&&g.1y.1i(6);7(p=="1R"||p=="27"){g.19=E.1j(6,"19");g.32=6.W.32}}7(g.32!=V)6.W.32="1Z";g.40=E.1s({},l);E.R(l,J(c,a){L e=1B E.2t(4A,g,c);7(/2g|1G|1I/.17(a))e[a=="2g"?f?"1G":"1I":a](l);N{L b=a.3X().1D(/^([+-]=)?([\\d+-.]+)(.*)$/),1Y=e.2m(P)||0;7(b){L d=2M(b[2]),2A=b[3]||"2S";7(2A!="2S"){4A.W[c]=(d||1)+2A;1Y=((d||1)/e.2m(P))*1Y;4A.W[c]=1Y+2A}7(b[1])d=((b[1]=="-="?-1:1)*d)+1Y;e.45(1Y,d,2A)}N e.45(1Y,a,"")}});K P})},2P:J(a,b){7(E.1q(a)||(a&&a.1k==1M)){b=a;a="2t"}7(!a||(1o a=="25"&&!b))K A(6[0],a);K 6.R(J(){7(b.1k==1M)A(6,a,b);N{A(6,a).1g(b);7(A(6,a).M==1)b.1i(6)}})},94:J(b,c){L a=E.3G;7(b)6.2P([]);6.R(J(){Q(L i=a.M-1;i>=0;i--)7(a[i].Y==6){7(c)a[i](P);a.72(i,1)}});7(!c)6.5p();K 6}});L A=J(b,c,a){7(!b)K 10;c=c||"2t";L q=E.O(b,c+"2P");7(!q||a)q=E.O(b,c+"2P",a?E.2I(a):[]);K q};E.1n.5p=J(a){a=a||"2t";K 6.R(J(){L q=A(6,a);q.4l();7(q.M)q[0].1i(6)})};E.1s({6P:J(b,a,c){L d=b&&b.1k==92?b:{1y:c||!c&&a||E.1q(b)&&b,2u:b,3Z:c&&a||a&&a.1k!=91&&a};d.2u=(d.2u&&d.2u.1k==51?d.2u:{90:8Z,9D:6T}[d.2u])||8X;d.5y=d.1y;d.1y=J(){7(d.2P!==S)E(6).5p();7(E.1q(d.5y))d.5y.1i(6)};K d},3Z:{70:J(p,n,b,a){K b+a*p},5j:J(p,n,b,a){K((-24.8V(p*24.8U)/2)+0.5)*a+b}},3G:[],3W:V,2t:J(b,c,a){6.11=c;6.Y=b;6.1l=a;7(!c.47)c.47={}}});E.2t.2l={4y:J(){7(6.11.30)6.11.30.1i(6.Y,[6.2J,6]);(E.2t.30[6.1l]||E.2t.30.4G)(6);7(6.1l=="1R"||6.1l=="27")6.Y.W.19="3D"},2m:J(a){7(6.Y[6.1l]!=V&&6.Y.W[6.1l]==V)K 6.Y[6.1l];L r=2M(E.1j(6.Y,6.1l,a));K r&&r>-8Q?r:2M(E.2o(6.Y,6.1l))||0},45:J(c,b,d){6.5B=(1B 3v()).3L();6.1Y=c;6.3h=b;6.2A=d||6.2A||"2S";6.2J=6.1Y;6.4B=6.4w=0;6.4y();L e=6;J t(a){K e.30(a)}t.Y=6.Y;E.3G.1g(t);7(E.3W==V){E.3W=53(J(){L a=E.3G;Q(L i=0;i<a.M;i++)7(!a[i]())a.72(i--,1);7(!a.M){6I(E.3W);E.3W=V}},13)}},1G:J(){6.11.47[6.1l]=E.1J(6.Y.W,6.1l);6.11.1G=P;6.45(0,6.2m());7(6.1l=="27"||6.1l=="1R")6.Y.W[6.1l]="8N";E(6.Y).1G()},1I:J(){6.11.47[6.1l]=E.1J(6.Y.W,6.1l);6.11.1I=P;6.45(6.2m(),0)},30:J(a){L t=(1B 3v()).3L();7(a||t>6.11.2u+6.5B){6.2J=6.3h;6.4B=6.4w=1;6.4y();6.11.40[6.1l]=P;L b=P;Q(L i 1p 6.11.40)7(6.11.40[i]!==P)b=S;7(b){7(6.11.19!=V){6.Y.W.32=6.11.32;6.Y.W.19=6.11.19;7(E.1j(6.Y,"19")=="2H")6.Y.W.19="3D"}7(6.11.1I)6.Y.W.19="2H";7(6.11.1I||6.11.1G)Q(L p 1p 6.11.40)E.1J(6.Y.W,p,6.11.47[p])}7(b&&E.1q(6.11.1y))6.11.1y.1i(6.Y);K S}N{L n=t-6.5B;6.4w=n/6.11.2u;6.4B=E.3Z[6.11.3Z||(E.3Z.5j?"5j":"70")](6.4w,n,0,1,6.11.2u);6.2J=6.1Y+((6.3h-6.1Y)*6.4B);6.4y()}K P}};E.2t.30={2v:J(a){a.Y.2v=a.2J},2x:J(a){a.Y.2x=a.2J},1w:J(a){E.1J(a.Y.W,"1w",a.2J)},4G:J(a){a.Y.W[a.1l]=a.2J+a.2A}};E.1n.5L=J(){L b=0,3b=0,Y=6[0],5l;7(Y)8M(E.14){L d=Y.1a,41=Y,1K=Y.1K,1L=Y.2i,5D=2d&&4s(5K)<8J&&!/a1/i.17(v),2T=E.1j(Y,"43")=="2T";7(Y.6G){L c=Y.6G();1b(c.26+24.2f(1L.1F.2v,1L.1h.2v),c.3b+24.2f(1L.1F.2x,1L.1h.2x));1b(-1L.1F.62,-1L.1F.60)}N{1b(Y.5G,Y.5F);2b(1K){1b(1K.5G,1K.5F);7(48&&!/^t(8H|d|h)$/i.17(1K.28)||2d&&!5D)2N(1K);7(!2T&&E.1j(1K,"43")=="2T")2T=P;41=/^1h$/i.17(1K.28)?41:1K;1K=1K.1K}2b(d&&d.28&&!/^1h|3q$/i.17(d.28)){7(!/^8G|1O.*$/i.17(E.1j(d,"19")))1b(-d.2v,-d.2x);7(48&&E.1j(d,"32")!="4d")2N(d);d=d.1a}7((5D&&(2T||E.1j(41,"43")=="4W"))||(48&&E.1j(41,"43")!="4W"))1b(-1L.1h.5G,-1L.1h.5F);7(2T)1b(24.2f(1L.1F.2v,1L.1h.2v),24.2f(1L.1F.2x,1L.1h.2x))}5l={3b:3b,26:b}}J 2N(a){1b(E.2o(a,"a8",P),E.2o(a,"a9",P))}J 1b(l,t){b+=4s(l)||0;3b+=4s(t)||0}K 5l}})();',62,631,'||||||this|if||||||||||||||||||||||||||||||||||||||function|return|var|length|else|data|true|for|each|false|document|type|null|style||elem||undefined|options|nodeName||browser|nodeType|event|test|arguments|display|parentNode|add|url|msie|window|indexOf|push|body|apply|css|constructor|prop|script|fn|typeof|in|isFunction|replace|extend|className|text|handle|opacity|div|complete|status|value|new|firstChild|match|filter|documentElement|show|dataType|hide|attr|offsetParent|doc|Array|trigger|table|call|break|height|try|cache|tbody|remove|success|catch|start|hidden||ready|get|split|Math|string|left|width|tagName|ret|global|while|map|safari|animate|max|toggle|toLowerCase|ownerDocument|bind|select|prototype|cur||curCSS|selected|handler|done|find|fx|duration|scrollLeft|id|scrollTop|special|opera|unit|nextSibling|stack|guid|toUpperCase|pushStack|button|none|makeArray|now|slice|target|parseFloat|border|exec|queue|isReady|events|px|fixed|timeout|delete|jsre|one|disabled|nth|step|name|overflow|inArray|removeChild|removeData|preventDefault|merge|appendChild|readyState|error|top|which|innerHTML|multiFilter|rl|trim|end|json|first|checked|async|param|elems|insertBefore|childNodes|html|encodeURIComponent|createElement|append|form|Date|unbind|color|grep|setTimeout|readyList|mouseleave|mouseenter|block|isXMLDoc|addEventListener|timers|is|password|last|runtimeStyle|getTime|xml|jQuery|domManip|ajax|src|callee|getElementsByTagName|selectedIndex|load|object|timerId|toString|has|easing|curAnim|offsetChild|args|position|stopPropagation|custom|props|orig|mozilla|accepts|clean|responseText|defaultView|visible|String|charCode|float|teardown|on|setup|nodeIndex|shift|javascript|currentStyle|application|child|RegExp|_|parseInt|previousSibling|dir|tr|state|empty|update|getAttribute|self|pos|setRequestHeader|input|jsonp|lastModified|_default|unload|ajaxSettings|unshift|getComputedStyle|styleSheets|getPropertyValue|lastToggle|mouseout|mouseover|GET|andSelf|relatedTarget|init|visibility|click|absolute|index|container|fix|outline|Number|removeAttribute|setInterval|prevObject|classFilter|not|unique|submit|file|after|windowData|deep|scroll|client|triggered|globalEval|jquery|sibling|swing|clone|results|wrapAll|triggerHandler|lastChild|dequeue|getResponseHeader|createTextNode|oldblock|checkbox|radio|handleError|fromElement|parsererror|old|00|Modified|startTime|ifModified|safari2|getWH|offsetTop|offsetLeft|active|values|getElementById|version|offset|bindReady|processData|val|contentType|ajaxSuccess|ajaxComplete|ajaxStart|serializeArray|notmodified|loaded|DOMContentLoaded|Width|ctrlKey|keyCode|clientTop|POST|clientLeft|clientX|pageX|exclusive|detachEvent|removeEventListener|swap|cloneNode|join|attachEvent|eval|ajaxStop|substr|head|parse|textarea|reset|image|zoom|odd|ajaxSend|even|before|username|prepend|expr|quickClass|uuid|quickID|quickChild|continue|textContent|appendTo|contents|evalScript|parent|defaultValue|ajaxError|setArray|compatMode|getBoundingClientRect|styleFloat|clearInterval|httpNotModified|nodeValue|100|alpha|_toggle|href|speed|throw|304|replaceWith|200|Last|colgroup|httpData|httpSuccess|beforeSend|eq|linear|concat|splice|fieldset|multiple|cssFloat|XMLHttpRequest|webkit|ActiveXObject|CSS1Compat|link|metaKey|scriptCharset|callback|col|pixelLeft|urlencoded|www|post|hasClass|getJSON|getScript|elements|serialize|black|keyup|keypress|solid|change|mousemove|mouseup|dblclick|resize|focus|blur|stylesheet|rel|doScroll|round|hover|padding|offsetHeight|mousedown|offsetWidth|Bottom|Top|keydown|clientY|Right|pageY|Left|toElement|srcElement|cancelBubble|returnValue|charAt|0n|substring|animated|header|noConflict|line|enabled|innerText|contains|only|weight|ajaxSetup|font|size|gt|lt|uFFFF|u0128|417|Boolean|inner|Height|toggleClass|removeClass|addClass|removeAttr|replaceAll|insertAfter|prependTo|contentWindow|contentDocument|wrap|iframe|children|siblings|prevAll|nextAll|prev|wrapInner|next|parents|maxLength|maxlength|readOnly|readonly|reverse|class|htmlFor|inline|able|boxModel|522|setData|compatible|with|1px|ie|getData|10000|ra|it|rv|PI|cos|userAgent|400|navigator|600|slow|Function|Object|array|stop|ig|NaN|fadeTo|option|fadeOut|fadeIn|setAttribute|slideToggle|slideUp|changed|slideDown|be|can|property|responseXML|content|1223|getAttributeNode|300|method|protocol|location|action|send|abort|cssText|th|td|cap|specified|Accept|With|colg|Requested|fast|tfoot|GMT|thead|1970|Jan|attributes|01|Thu|leg|Since|If|opt|Type|Content|embed|open|area|XMLHTTP|hr|Microsoft|onreadystatechange|onload|meta|adobeair|charset|http|1_|img|br|plain|borderLeftWidth|borderTopWidth|abbr'.split('|'),0,{}))
\ No newline at end of file
Binary file MoinMoin/support/werkzeug/debug/shared/less.png has changed
Binary file MoinMoin/support/werkzeug/debug/shared/more.png has changed
Binary file MoinMoin/support/werkzeug/debug/shared/source.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/debug/shared/style.css	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,93 @@
+body, input  { font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
+               'Verdana', sans-serif; background-color: #AFC1C4; color: #000;
+               text-align: center; margin: 1em; padding: 0; font-size: 15px; }
+input        { background-color: #fff; margin: 0; text-align: left; }
+a            { color: #11557C; }
+a:hover      { color: #177199; }
+pre, code, table.source,
+textarea     { font-family: 'Consolas', 'Deja Vu Sans Mono',
+               'Bitstream Vera Sans Mono', monospace; font-size: 13px; }
+
+div.debugger { text-align: left; padding: 12px; margin: auto;
+               border: 1px solid #aaa; background-color: white; }
+h1           { color: #11557C; font-size: 30px; margin: 0 0 0.3em 0; }
+div.detail p { margin: 0 0 8px 13px; font-size: 14px; }
+div.explanation { margin: 13px; font-size: 11px; }
+div.footer   { background-color: #E3EFF1; font-size: 0.8em; text-align: right;
+               padding: 6px 8px 6px 0; margin: 30px -12px -12px -12px;
+               color: #86989B; }
+
+h2           { font-size: 16px; margin: 1.3em 0 0.0 0; padding: 5px;
+               background-color: #11557C; color: white; }
+h2 em        { font-style: normal; color: #A5D6D9; font-weight: normal; }
+
+div.traceback, div.plain { background-color: #eee!important; border: 1px solid #ccc;
+                           margin: 0 0 1em 0; padding: 10px; }
+div.plain p      { margin: 0; }
+div.plain textarea,
+div.plain pre { margin: 10px 0 0 0; padding: 4px; background-color: #333;
+                border: 1px solid #111; color: white; }
+div.plain textarea { width: 99%; height: 300px; }
+div.traceback h3 { font-size: 1em; margin: 0 0 0.8em 0; }
+div.traceback ul { list-style: none; margin: 0; padding: 0 0 0 1em; }
+div.traceback h4 { font-size: 13px; font-weight: normal; margin: 0.7em 0 0.1em 0; }
+div.traceback pre { margin: 0; padding: 5px 0 3px 15px;
+                    background-color: #ccc; border-top: 1px solid #aaa;
+                    border-left: 1px solid #aaa; border-right: 1px solid #fafafa;
+                    border-bottom: 1px solid #fafafa; }
+div.traceback pre,
+div.box table.source { white-space: pre-wrap;       /* css-3 should we be so lucky... */
+                       white-space: -moz-pre-wrap;  /* Mozilla, since 1999 */
+                       white-space: -pre-wrap;      /* Opera 4-6 ?? */
+                       white-space: -o-pre-wrap;    /* Opera 7 ?? */
+                       word-wrap: break-word;       /* Internet Explorer 5.5+ */
+                       _white-space: pre;           /* IE only hack to re-specify in
+                                                    addition to word-wrap  */ }
+div.traceback pre:hover { background-color: #fafafa; color: black; cursor: pointer; }
+div.traceback blockquote { margin: 1em 0 0 0; padding: 0; }
+div.traceback img { float: right; padding: 2px; margin: -3px 2px 0 0; display: none; }
+div.traceback img:hover { background-color: #ddd; cursor: pointer; }
+div.traceback pre:hover img { display: block; }
+
+pre.console { background-color: #fafafa!important; color: black; padding: 5px!important;
+              margin: 3px 0 0 0!important; cursor: default!important;
+              max-height: 400px; overflow: auto; }
+pre.console form { color: #555; }
+pre.console input { background-color: #fafafa; color: #555;
+                    width: 90%; font-family: 'Consolas', 'Deja Vu Sans Mono',
+                    'Bitstream Vera Sans Mono', monospace; font-size: 13px;
+                     border: none!important; }
+
+span.string { color: #30799B; }
+span.number { color: #9C1A1C; }
+span.object { color: #485F6E; }
+span.extended { opacity: 0.5; }
+span.extended:hover { opacity: 1; }
+a.toggle { text-decoration: none; background-repeat: no-repeat;
+           background-position: center center;
+           background-image: url(./__debugger__?cmd=resource&f=more.png); }
+a.toggle:hover { background-color: #444; }
+a.open { background-image: url(./__debugger__?cmd=resource&f=less.png); }
+
+pre.console div.traceback { margin: 5px 0 5px 25px; white-space: normal; }
+pre.console div.traceback h3 { background-color: #555; color: white;
+                               margin: -10px -10px 5px -10px; padding: 5px; }
+pre.console div.traceback pre:hover { background-color: #ccc; cursor: default; }
+
+pre.console div.box { margin: 5px 0 5px 25px; white-space: normal;
+                      border: 1px solid #ddd; }
+pre.console div.box h3 { background-color: #555; color: white;
+                         margin: 0; padding: 5px; }
+pre.console div.box div.repr { padding: 8px; background-color: white; }
+pre.console div.box table { margin-top: 6px; }
+pre.console div.box pre.help { background-color: white; font-size: 12px; }
+pre.console div.box pre.help:hover { cursor: default; }
+pre.console table tr { vertical-align: top; }
+div.box table.source { background-color: #fafafa; font-size: 12px;
+                       border-collapse: collapse; width: 100%; }
+div.box table.source td { border-top: 1px solid #eee; padding: 4px 0 4px 10px; }
+div.box table.source td.lineno { color: #999; padding-right: 10px; width: 1px; }
+div.box table.source tr.in-frame { background-color: #D6EEFF; }
+div.box table.source tr.current { background-color: white; }
+div.sourceview { max-height: 400px; overflow: auto; border: 1px solid #ccc; }
+div.console { border: 1px solid #ccc; padding: 4px; background-color: #fafafa; }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/debug/shared/vartable.tmpl	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,16 @@
+<table class="vars">
+<% if type == 'empty' %>
+  <tr><th>no data given</th></tr>
+<% elif type == 'simple' %>
+  <tr><td class="value">$escape(value)</td></tr>
+<% elif type == 'dict' %>
+  <tr><th>Name</th><th>Value</th></tr>
+  <% for key, item in value %>
+  <tr><td class="name">$escape(key)</td><td class="value">$escape(item)</td></tr>
+  <% endfor %>
+<% elif type == 'list' %>
+  <% for item in value %>
+  <tr><td class="value">$escape(item)</td></tr>
+  <% endfor %>
+<% endif %>
+</table>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/debug/tbtools.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,293 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.debug.tbtools
+    ~~~~~~~~~~~~~~~~~~~~~~
+
+    This module provides various traceback related utility functions.
+
+    :copyright: Copyright 2008 by Armin Ronacher.
+    :license: BSD.
+"""
+import re
+import os
+import sys
+import inspect
+import traceback
+import codecs
+from tokenize import TokenError
+from werkzeug.utils import cached_property
+from werkzeug.debug.console import Console
+from werkzeug.debug.utils import render_template
+
+_coding_re = re.compile(r'coding[:=]\s*([-\w.]+)')
+_line_re = re.compile(r'^(.*?)$(?m)')
+_funcdef_re = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
+UTF8_COOKIE = '\xef\xbb\xbf'
+
+system_exceptions = (SystemExit, KeyboardInterrupt)
+try:
+    system_exceptions += (GeneratorExit,)
+except NameError:
+    pass
+
+
+def get_current_traceback(ignore_system_exceptions=False,
+                          show_hidden_frames=False, skip=0):
+    """Get the current exception info as `Traceback` object.  Per default
+    calling this method will reraise system exceptions such as generator exit,
+    system exit or others.  This behavior can be disabled by passing `False`
+    to the function as first parameter.
+    """
+    exc_type, exc_value, tb = sys.exc_info()
+    if ignore_system_exceptions and exc_type in system_exceptions:
+        raise
+    for x in xrange(skip):
+        if tb.tb_next is None:
+            break
+        tb = tb.tb_next
+    tb = Traceback(exc_type, exc_value, tb)
+    if not show_hidden_frames:
+        tb.filter_hidden_frames()
+    return tb
+
+
+class Line(object):
+    """Helper for the source renderer."""
+    __slots__ = ('lineno', 'code', 'in_frame', 'current')
+
+    def __init__(self, lineno, code):
+        self.lineno = lineno
+        self.code = code
+        self.in_frame = False
+        self.current = False
+
+    def classes(self):
+        rv = ['line']
+        if self.in_frame:
+            rv.append('in-frame')
+        if self.current:
+            rv.append('current')
+        return rv
+    classes = property(classes)
+
+
+class Traceback(object):
+    """Wraps a traceback."""
+
+    def __init__(self, exc_type, exc_value, tb):
+        self.exc_type = exc_type
+        self.exc_value = exc_value
+        if not isinstance(exc_type, str):
+            exception_type = exc_type.__name__
+            if exc_type.__module__ not in ('__builtin__', 'exceptions'):
+                exception_type = exc_type.__module__ + '.' + exception_type
+        else:
+            exception_type = exc_type
+        self.exception_type = exception_type
+
+        # we only add frames to the list that are not hidden.  This follows
+        # the the magic variables as defined by paste.exceptions.collector
+        self.frames = []
+        while tb:
+            self.frames.append(Frame(exc_type, exc_value, tb))
+            tb = tb.tb_next
+
+    def filter_hidden_frames(self):
+        """Remove the frames according to the paste spec."""
+        new_frames = []
+        hidden = False
+        for frame in self.frames:
+            hide = frame.hide
+            if hide in ('before', 'before_and_this'):
+                new_frames = []
+                hidden = False
+                if hide == 'before_and_this':
+                    continue
+            elif hide in ('reset', 'reset_and_this'):
+                hidden = False
+                if hide == 'reset_and_this':
+                    continue
+            elif hide in ('after', 'after_and_this'):
+                hidden = True
+                if hide == 'after_and_this':
+                    continue
+            elif hide or hidden:
+                continue
+            new_frames.append(frame)
+
+        # if the last frame is missing something went terrible wrong :(
+        if self.frames[-1] in new_frames:
+            self.frames[:] = new_frames
+
+    def is_syntax_error(self):
+        """Is it a syntax error?"""
+        return isinstance(self.exc_value, SyntaxError)
+    is_syntax_error = property(is_syntax_error)
+
+    def exception(self):
+        """String representation of the exception."""
+        buf = traceback.format_exception_only(self.exc_type, self.exc_value)
+        return ''.join(buf).strip().decode('utf-8', 'replace')
+    exception = property(exception)
+
+    def log(self, logfile=None):
+        """Log the ASCII traceback into a file object."""
+        if logfile is None:
+            logfile = sys.stderr
+        tb = self.plaintext.encode('utf-8', 'replace').rstrip() + '\n'
+        logfile.write(tb)
+
+    def paste(self):
+        """Create a paste and return the paste id."""
+        from xmlrpclib import ServerProxy
+        srv = ServerProxy('http://paste.pocoo.org/xmlrpc/')
+        return srv.pastes.newPaste('pytb', self.plaintext)
+        return '{"url": "http://paste.pocoo.org/show/%d/", "id": %d}' % \
+               (paste_id, paste_id)
+
+    def render_summary(self, include_title=True):
+        """Render the traceback for the interactive console."""
+        return render_template('traceback_summary.html', traceback=self,
+                               include_title=include_title)
+
+    def render_full(self, evalex=False):
+        """Render the Full HTML page with the traceback info."""
+        return render_template('traceback_full.html', traceback=self,
+                               evalex=evalex)
+
+    def plaintext(self):
+        return render_template('traceback_plaintext.html', traceback=self)
+    plaintext = cached_property(plaintext)
+
+    id = property(lambda x: id(x))
+
+
+class Frame(object):
+    """A single frame in a traceback."""
+
+    def __init__(self, exc_type, exc_value, tb):
+        self.lineno = tb.tb_lineno
+        self.function_name = tb.tb_frame.f_code.co_name
+        self.locals = tb.tb_frame.f_locals
+        self.globals = tb.tb_frame.f_globals
+
+        fn = inspect.getsourcefile(tb) or inspect.getfile(tb)
+        if fn[-4:] in ('.pyo', '.pyc'):
+            fn = fn[:-1]
+        # if it's a file on the file system resolve the real filename.
+        if os.path.isfile(fn):
+            fn = os.path.realpath(fn)
+        self.filename = fn
+        self.module = self.globals.get('__name__')
+        self.loader = self.globals.get('__loader__')
+        self.code = tb.tb_frame.f_code
+
+        # support for paste's traceback extensions
+        self.hide = self.locals.get('__traceback_hide__', False)
+        info = self.locals.get('__traceback_info__')
+        if info is not None:
+            try:
+                info = unicode(info)
+            except UnicodeError:
+                info = str(info).decode('utf-8', 'replace')
+        self.info = info
+
+    def render(self):
+        """Render a single frame in a traceback."""
+        return render_template('frame.html', frame=self)
+
+    def render_source(self):
+        """Render the sourcecode."""
+        lines = [Line(idx + 1, x) for idx, x in enumerate(self.sourcelines)]
+
+        # find function definition and mark lines
+        if hasattr(self.code, 'co_firstlineno'):
+            lineno = self.code.co_firstlineno - 1
+            while lineno > 0:
+                if _funcdef_re.match(lines[lineno].code):
+                    break
+                lineno -= 1
+            try:
+                offset = len(inspect.getblock([x.code + '\n' for x
+                                               in lines[lineno:]]))
+            except TokenError:
+                offset = 0
+            for line in lines[lineno:lineno + offset]:
+                line.in_frame = True
+
+        # mark current line
+        try:
+            lines[self.lineno - 1].current = True
+        except IndexError:
+            pass
+
+        return render_template('source.html', frame=self, lines=lines)
+
+    def eval(self, code, mode='single'):
+        """Evaluate code in the context of the frame."""
+        if isinstance(code, basestring):
+            if isinstance(code, unicode):
+                code = UTF8_COOKIE + code.encode('utf-8')
+            code = compile(code, '<interactive>', mode)
+        if mode != 'exec':
+            return eval(code, self.globals, self.locals)
+        exec code in self.globals, self.locals
+
+    def sourcelines(self):
+        """The sourcecode of the file as list of unicode strings."""
+        # get sourcecode from loader or file
+        source = None
+        if self.loader is not None:
+            if hasattr(self.loader, 'get_source'):
+                source = self.loader.get_source(self.module)
+            elif hasattr(self.loader, 'get_source_by_code'):
+                source = self.loader.get_source_by_code(self.code)
+        if source is None:
+            try:
+                f = file(self.filename)
+            except IOError:
+                return []
+            try:
+                source = f.read()
+            finally:
+                f.close()
+
+        # already unicode?  return right away
+        if isinstance(source, unicode):
+            return source.splitlines()
+
+        # yes. it should be ascii, but we don't want to reject too many
+        # characters in the debugger if something breaks
+        charset = 'utf-8'
+        if source.startswith(UTF8_COOKIE):
+            source = source[3:]
+        else:
+            for idx, match in enumerate(_line_re.finditer(source)):
+                match = _line_re.search(match.group())
+                if match is not None:
+                    charset = match.group(1)
+                    break
+                if idx > 1:
+                    break
+
+        # on broken cookies we fall back to utf-8 too
+        try:
+            codecs.lookup(charset)
+        except LookupError:
+            charset = 'utf-8'
+
+        return source.decode(charset, 'replace').splitlines()
+    sourcelines = cached_property(sourcelines)
+
+    def current_line(self):
+        try:
+            return self.sourcelines[self.lineno - 1]
+        except IndexError:
+            return u''
+    current_line = property(current_line)
+
+    def console(self):
+        return Console(self.globals, self.locals)
+    console = cached_property(console)
+
+    id = property(lambda x: id(x))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/debug/templates/console.html	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+  <head>
+    <title>Console // Werkzeug Debugger</title>
+    <link rel="stylesheet" href="./__debugger__?cmd=resource&amp;f=style.css" type="text/css">
+    <script type="text/javascript" src="./__debugger__?cmd=resource&amp;f=jquery.js"></script>
+    <script type="text/javascript" src="./__debugger__?cmd=resource&amp;f=debugger.js"></script>
+    <script type="text/javascript">
+      var EVALEX = true,
+          CONSOLE_MODE = true;
+    </script>
+  </head>
+  <body>
+    <div class="debugger">
+      <h1>Interactive Console</h1>
+      <div class="explanation">
+        In this console you can execute Python expressions in the context of the
+        application.  The initial namespace was created by the debugger automatically.
+      </div>
+      <div class="console"><div class="inner">The Console requires JavaScript.</div></div>
+      <div class="footer">
+        Brought to you by <strong class="arthur">DON'T PANIC</strong>, your
+        friendly Werkzeug powered traceback interpreter.
+      </div>
+    </div>
+  </body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/debug/templates/dump_object.html	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,14 @@
+<div class="box">
+  <h3>$escape(title)</h3>
+  <% if repr %>
+    <div class="repr">$repr</div>
+  <% endif %>
+  <table>
+  <% for key, value in items %>
+    <tr>
+      <th>$escape(key)</th>
+      <td>$value</td>
+    </tr>
+  <% endfor %>
+  </table>
+</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/debug/templates/frame.html	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,5 @@
+<div class="frame" id="frame-$frame.id">
+  <h4>File <cite>"$escape(frame.filename)"</cite>, line <em>$frame.lineno</em>,
+      in <code>$escape(frame.function_name)</code></h4>
+  <pre>${escape(frame.current_line.strip())}</pre>
+</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/debug/templates/help_command.html	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,10 @@
+<%py missing = object() %>
+<div class="box">
+  <% if title and text %>
+    <h3>$title</h3>
+    <pre class="help">$text</pre>
+  <% else %>
+    <h3>Help</h3>
+    <p>Type help(object) for help abuot object.</p>
+  <% endif %>
+</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/debug/templates/source.html	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,8 @@
+<table class="source">
+<% for line in lines %>
+  <tr class="${' '.join(line.classes)}">
+    <td class="lineno">${line.lineno}</td>
+    <td>$escape(line.code)</td>
+  </tr>
+<% endfor %>
+</table>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/debug/templates/traceback_full.html	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,55 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+  <head>
+    <title>$escape(traceback.exception) // Werkzeug Debugger</title>
+    <link rel="stylesheet" href="./__debugger__?cmd=resource&amp;f=style.css" type="text/css">
+    <script type="text/javascript" src="./__debugger__?cmd=resource&amp;f=jquery.js"></script>
+    <script type="text/javascript" src="./__debugger__?cmd=resource&amp;f=debugger.js"></script>
+    <script type="text/javascript">
+      var TRACEBACK = $traceback.id,
+          CONSOLE_MODE = false,
+          EVALEX = ${evalex and 'true' or 'false'};
+    </script>
+  </head>
+  <body>
+    <div class="debugger">
+      <h1>$escape(traceback.exception_type)</h1>
+      <div class="detail">
+        <p class="errormsg">$escape(traceback.exception)</p>
+      </div>
+      <h2 class="traceback">Traceback <em>(most recent call last)</em></h2>
+      $traceback.render_summary(include_title=False)
+      <div class="plain">
+        <form action="http://paste.pocoo.org/" method="post">
+          <p>
+            <input type="hidden" name="language" value="pytb">
+            This is the Copy/Paste friendly version of the traceback.  <span
+            class="pastemessage">You can also paste this traceback into the public
+            lodgeit pastebin: <input type="submit" value="create paste"></span>
+          </p>
+          <textarea cols="50" rows="10" name="code" readonly>$escape(traceback.plaintext)</textarea>
+        </form>
+      </div>
+      <div class="explanation">
+        The debugger cought an exception in your WSGI application.  You can now
+        look at the traceback which lead to the error.  <span class="nojavascript">
+        If you enable JavaScript you can also use additional features such as code
+        execution (if the evalex feature is enabled), automatic pasting of the
+        exceptions and much more.</span>
+      </div>
+      <div class="footer">
+        Brought to you by <strong class="arthur">DON'T PANIC</strong>, your
+        friendly Werkzeug powered traceback interpreter.
+      </div>
+    </div>
+  </body>
+</html>
+<!--
+
+<%py
+  import re
+  print re.sub('-{2,}', '-', traceback.plaintext)
+%>
+
+-->
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/debug/templates/traceback_plaintext.html	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,6 @@
+Traceback (most recent call last):
+<% for frame in traceback.frames %>
+  File "$frame.filename", line $frame.lineno, in $frame.function_name
+    $frame.current_line.strip()
+<% endfor %>
+$traceback.exception
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/debug/templates/traceback_summary.html	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,23 @@
+<div class="traceback">
+  <% if traceback.is_syntax_error %>
+    <% if include_title %>
+      <h3>Syntax Error</h3>
+    <% endif %>
+    <ul>
+    <% for frame in traceback.frames %>
+      <li>$frame.render()</li>
+    <% endfor %>
+    </ul>
+    <pre>$escape(traceback.exception)</pre>
+  <% else %>
+    <% if include_title %>
+      <h3>Traceback <em>(most recent call last)</em>:</h3>
+    <% endif %>
+    <ul>
+    <% for frame in traceback.frames %>
+      <li<% if frame.info %> title="$escape(frame.info, True)"<% endif %>>$frame.render()</li>
+    <% endfor %>
+    </ul>
+    <blockquote>$escape(traceback.exception)</blockquote>
+  <% endif %>
+</div>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/debug/utils.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.debug.utils
+    ~~~~~~~~~~~~~~~~~~~~
+
+    Various other utilities.
+
+    :copyright: Copyright 2008 by Armin Ronacher.
+    :license: BSD.
+"""
+from os.path import join, dirname
+from werkzeug.templates import Template
+
+
+def get_template(filename):
+    return Template.from_file(join(dirname(__file__), 'templates', filename))
+
+
+def render_template(template_filename, **context):
+    return get_template(template_filename).render(**context)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/exceptions.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,456 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.exceptions
+    ~~~~~~~~~~~~~~~~~~~
+
+    This module implements a number of Python exceptions you can raise from
+    within your views to trigger a standard non 200 response.
+
+
+    Usage Example
+    -------------
+
+    ::
+
+        from werkzeug import BaseRequest, responder
+        from werkzeug.exceptions import HTTPException, NotFound
+
+        def view(request):
+            raise NotFound()
+
+        @responder
+        def application(environ, start_response):
+            request = BaseRequest(environ)
+            try:
+                return view(request)
+            except HTTPException, e:
+                return e
+
+
+    As you can see from this example those exceptions are callable WSGI
+    applications.  Because of Python 2.3 / 2.4 compatibility those do not
+    extend from the response objects but only from the python exception
+    class.
+
+    As a matter of fact they are not Werkzeug response objects.  However you
+    can get a response object by calling ``get_response()`` on a HTTP
+    exception.
+
+    Keep in mind that you have to pass an environment to ``get_response()``
+    because some errors fetch additional information from the WSGI
+    environment.
+
+    If you want to hook in a different exception page to say, an 404 status
+    code, you can add a second except for a specific subclass of an error::
+
+        @responder
+        def application(environ, start_response):
+            request = BaseRequest(environ)
+            try:
+                return view(request)
+            except NotFound, e:
+                return not_found(request)
+            except HTTPException, e:
+                return e
+
+
+    :copyright: 2007-2008 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+import sys
+from werkzeug._internal import HTTP_STATUS_CODES
+
+
+class HTTPException(Exception):
+    """
+    Baseclass for all HTTP exceptions.  This exception can be called as WSGI
+    application to render a default error page or you can catch the subclasses
+    of it independently and render nicer error messages.
+    """
+
+    code = None
+    description = None
+
+    def __init__(self, description=None):
+        Exception.__init__(self, '%d %s' % (self.code, self.name))
+        if description is not None:
+            self.description = description
+
+    def wrap(cls, exception, name=None):
+        """
+        This method returns a new subclass of the exception provided that
+        also is a subclass of `BadRequest`.
+        """
+        class newcls(cls, exception):
+            def __init__(self, arg=None, description=None):
+                cls.__init__(self, description)
+                exception.__init__(self, arg)
+        newcls.__module__ = sys._getframe(1).f_globals.get('__name__')
+        newcls.__name__ = name or cls.__name__ + exception.__name__
+        return newcls
+    wrap = classmethod(wrap)
+
+    def name(self):
+        """The status name."""
+        return HTTP_STATUS_CODES[self.code]
+    name = property(name, doc=name.__doc__)
+
+    def get_description(self, environ):
+        """Get the description."""
+        return self.description
+
+    def get_body(self, environ):
+        """Get the HTML body."""
+        return (
+            '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n'
+            '<title>%(code)s %(name)s</title>\n'
+            '<h1>%(name)s</h1>\n'
+            '%(description)s\n'
+        ) % {
+            'code':         self.code,
+            'name':         escape(self.name),
+            'description':  self.get_description(environ)
+        }
+
+    def get_headers(self, environ):
+        """Get a list of headers."""
+        return [('Content-Type', 'text/html')]
+
+    def get_response(self, environ):
+        """Get a response object."""
+        # lazyly imported for various reasons.  For one can use the exceptions
+        # with custom responses (testing exception instances against types) and
+        # so we don't ever have to import the wrappers, but also because there
+        # are ciruclar dependencies when bootstrapping the module.
+        from werkzeug.wrappers import BaseResponse
+        headers = self.get_headers(environ)
+        return BaseResponse(self.get_body(environ), self.code, headers)
+
+    def __call__(self, environ, start_response):
+        """Call the exception as WSGI application."""
+        response = self.get_response(environ)
+        return response(environ, start_response)
+
+
+class _ProxyException(HTTPException):
+    """
+    An HTTP exception that expands renders a WSGI application on error.
+    """
+
+    def __init__(self, response):
+        Exception.__init__(self, 'proxy exception for %r' % response)
+        self.response = response
+
+    def get_response(self, environ):
+        return self.response
+
+
+class BadRequest(HTTPException):
+    """
+    *400* `Bad Request`
+
+    Raise if the browser send something to the application the application
+    or server cannot handle.
+    """
+    code = 400
+    description = (
+        '<p>The browser (or proxy) sent a request that this server could '
+        'not understand.</p>'
+    )
+
+
+class Unauthorized(HTTPException):
+    """
+    *401* `Unauthorized`
+
+    Raise if the user is not authorized.  Also used if you want to use HTTP
+    basic auth.
+    """
+    code = 401
+    description = (
+        '<p>The server could not verify that you are authorized to access '
+        'the URL requested.  You either supplied the wrong credentials (e.g.'
+        ', bad password), or your browser doesn\'t understand how to supply '
+        'the credentials required.</p><p>In case you are allowed to request '
+        'the document, please check your user-id and password and try '
+        'again.</p>'
+    )
+
+
+class Forbidden(HTTPException):
+    """
+    *403* `Forbidden`
+
+    Raise if the user doesn't have the permission for the requested resource
+    but was authenticated.
+    """
+    code = 403
+    description = (
+        '<p>You don\'t have the permission to access the requested resource. '
+        'It is either read-protected or not readable by the server.</p>'
+    )
+
+
+class NotFound(HTTPException):
+    """
+    *404* `Not Found`
+
+    Raise if a resource does not exist and never existed.
+    """
+    code = 404
+    description = (
+        '<p>The requested URL was not found on the server.</p>'
+        '<p>If you entered the URL manually please check your spelling and '
+        'try again.</p>'
+    )
+
+
+class MethodNotAllowed(HTTPException):
+    """
+    *405* `Method Not Allowed`
+
+    Raise if the server used a method the resource does not handle.  For
+    example `POST` if the resource is view only.  Especially useful for REST.
+
+    The first argument for this exception should be a list of allowed methods.
+    Strictly speaking the response would be invalid if you don't provide valid
+    methods in the header which you can do with that list.
+    """
+    code = 405
+
+    def __init__(self, valid_methods=None, description=None):
+        """Takes an optional list of valid http methods
+        starting with werkzeug 0.3 the list will be mandatory."""
+        HTTPException.__init__(self, description)
+        self.valid_methods = valid_methods
+
+    def get_headers(self, environ):
+        headers = HTTPException.get_headers(self, environ)
+        if self.valid_methods:
+            headers.append(('Allow', ', '.join(self.valid_methods)))
+        return headers
+
+    def get_description(self, environ):
+        m = escape(environ.get('REQUEST_METHOD', 'GET'))
+        return '<p>The method %s is not allowed for the requested URL.</p>' % m
+
+
+class NotAcceptable(HTTPException):
+    """
+    *406* `Not Acceptable`
+
+    Raise if the server cant return any content conforming to the
+    `Accept` headers of the client.
+    """
+    code = 406
+
+    description = (
+        '<p>The resource identified by the request is only capable of '
+        'generating response entities which have content characteristics '
+        'not acceptable according to the accept headers sent in the '
+        'request.</p>'
+        )
+
+
+class RequestTimeout(HTTPException):
+    """
+    *408* `Request Timeout`
+
+    Raise to signalize a timeout.
+    """
+    code = 408
+    description = (
+        '<p>The server closed the network connection because the browser '
+        'didn\'t finish the request within the specified time.</p>'
+    )
+
+
+class Gone(HTTPException):
+    """
+    *410* `Gone`
+
+    Raise if a resource existed previously and went away without new location.
+    """
+    code = 410
+    description = (
+        '<p>The requested URL is no longer available on this server and '
+        'there is no forwarding address.</p><p>If you followed a link '
+        'from a foreign page, please contact the author of this page.'
+    )
+
+
+class LengthRequired(HTTPException):
+    """
+    *411* `Length Required`
+
+    Raise if the browser submitted data but no ``Content-Length`` header which
+    is required for the kind of processing the server does.
+    """
+    code = 411
+    description = (
+        '<p>A request with this method requires a valid <code>Content-'
+        'Lenght</code> header.</p>'
+    )
+
+
+class PreconditionFailed(HTTPException):
+    """
+    *412* `Precondition Failed`
+
+    Status code used in combination with ``If-Match``, ``If-None-Match``, or
+    ``If-Unmodified-Since``.
+    """
+    code = 412
+    description = (
+        '<p>The precondition on the request for the URL failed positive '
+        'evaluation.</p>'
+    )
+
+
+class RequestEntityTooLarge(HTTPException):
+    """
+    *413* `Request Entity Too Large`
+
+    The status code one should return if the data submitted exceeded a given
+    limit.
+    """
+    code = 413
+    description = (
+        '<p>The data value transmitted exceed the capacity limit.</p>'
+    )
+
+
+class RequestURITooLarge(HTTPException):
+    """
+    *414* `Request URI Too Large`
+
+    Like *413* but for too long URLs.
+    """
+    code = 414
+    description = (
+        '<p>The length of the requested URL exceeds the capacity limit '
+        'for this server.  The request cannot be processed.</p>'
+    )
+
+
+class UnsupportedMediaType(HTTPException):
+    """
+    *415* `Unsupported Media Type`
+
+    The status code returned if the server is unable to handle the media type
+    the client transmitted.
+    """
+    code = 415
+    description = (
+        '<p>The server does not support the media type transmitted in '
+        'the request.</p>'
+    )
+
+
+class InternalServerError(HTTPException):
+    """
+    *500* `Internal Server Error`
+
+    Raise if an internal server error occoured.  This is a good fallback if an
+    unknown error occoured in the dispatcher.
+    """
+    code = 500
+    description = (
+        '<p>The server encountered an internal error and was unable to '
+        'complete your request.  Either the server is overloaded or there '
+        'is an error in the application.</p>'
+    )
+
+
+class NotImplemented(HTTPException):
+    """
+    *501* `Not Implemented`
+
+    Raise if the application does not support the action requested by the
+    browser.
+    """
+    code = 501
+    description = (
+        '<p>The server does not support the action requested by the '
+        'browser.</p>'
+    )
+
+
+class BadGateway(HTTPException):
+    """
+    *502* `Bad Gateway`
+
+    If you do proxing in your application you should return this status code
+    if you received an invalid response from the upstream server it accessed
+    in attempting to fulfill the request.
+    """
+    code = 502
+    description = (
+        '<p>The proxy server received an invalid response from an upstream '
+        'server.</p>'
+    )
+
+
+class ServiceUnavailable(HTTPException):
+    """
+    *503* `Service Unavailable`
+
+    Status code you should return if a service is temporarily unavailable.
+    """
+    code = 503
+    description = (
+        '<p>The server is temporarily unable to service your request due to '
+        'maintenance downtime or capacity problems.  Please try again '
+        'later.</p>'
+    )
+
+
+default_exceptions = {}
+__all__ = ['HTTPException']
+
+def _find_exceptions():
+    for name, obj in globals().iteritems():
+        try:
+            if getattr(obj, 'code', None) is not None:
+                default_exceptions[obj.code] = obj
+                __all__.append(obj.__name__)
+        except TypeError:
+            continue
+_find_exceptions()
+del _find_exceptions
+
+
+#: raised by the request functions if they were unable to decode the
+#: incomding data properly.
+HTTPUnicodeError = BadRequest.wrap(UnicodeError, 'HTTPUnicodeError')
+
+
+class Aborter(object):
+    """
+    When passed a dict of code -> exception items it can be used as
+    callable that raises exceptions.  If the first argument to the
+    callable is a integer it will be looked up in the mapping, if it's
+    a WSGI application it will be raised in a proxy exception.
+
+    The rest of the arguments are forwarded to the exception constructor.
+    """
+
+    def __init__(self, mapping=None, extra=None):
+        if mapping is None:
+            mapping = default_exceptions
+        self.mapping = dict(mapping)
+        if extra is not None:
+            self.mapping.update(extra)
+
+    def __call__(self, code, *args, **kwargs):
+        if not args and not kwargs and not isinstance(code, (int, long)):
+            raise _ProxyException(code)
+        if code not in self.mapping:
+            raise LookupError('no exception for %r' % code)
+        raise self.mapping[code](*args, **kwargs)
+
+abort = Aborter()
+
+
+# imported here because of circular dependencies of werkzeug.utils
+from werkzeug.utils import escape
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/http.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,834 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.http
+    ~~~~~~~~~~~~~
+
+    Werkzeug comes with a bunch of utilties that help Werkzeug to deal with
+    HTTP data.  Most of the classes and functions provided by this module are
+    used by the wrappers, but they are useful on their own too, especially if
+    the response and request objects are not used.
+
+    This covers some of the more HTTP centric features of WSGI, some other
+    utilities such as cookie handling are documented in the `werkzeug.utils`
+    module.
+
+
+    :copyright: 2007-2008 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+import re
+import rfc822
+from urllib2 import parse_http_list as _parse_list_header
+from datetime import datetime
+try:
+    from hashlib import md5
+except ImportError:
+    from md5 import new as md5
+try:
+    set = set
+    frozenset = frozenset
+except NameError:
+    from sets import Set as set, ImmutableSet as frozenset
+from werkzeug._internal import _patch_wrapper, _UpdateDict, HTTP_STATUS_CODES
+
+
+_accept_re = re.compile(r'([^\s;,]+)(?:[^,]*?;\s*q=(\d*(?:\.\d+)?))?')
+_token_chars = frozenset("!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                         '^_`abcdefghijklmnopqrstuvwxyz|~')
+_etag_re = re.compile(r'([Ww]/)?(?:"(.*?)"|(.*?))(?:\s*,\s*|$)')
+
+
+class Accept(list):
+    """An `Accept` object is just a list subclass for lists of
+    ``(value, quality)`` tuples.  It is automatically sorted by quality.
+    """
+
+    def __init__(self, values=()):
+        if values is None:
+            list.__init__(self)
+            self.provided = False
+        else:
+            self.provided = True
+            values = [(a, b) for b, a in values]
+            values.sort()
+            values.reverse()
+            list.__init__(self, [(a, b) for b, a in values])
+
+    def __getitem__(self, key):
+        """Beside index lookup (getting item n) you can also pass it a string
+        to get the quality for the item.  If the item is not in the list, the
+        returned quality is ``0``.
+        """
+        if isinstance(key, basestring):
+            for value in self:
+                if value[0] == key:
+                    return value[1]
+            return 0
+        return list.__getitem__(self, key)
+
+    def __contains__(self, key):
+        return self.find(key) > -1
+
+    def __repr__(self):
+        return '%s(%s)' % (
+            self.__class__.__name__,
+            list.__repr__(self)
+        )
+
+    def index(self, key):
+        """Get the position of en entry or raise `IndexError`."""
+        rv = self.find(key)
+        if rv < 0:
+            raise IndexError(key)
+        return key
+
+    def find(self, key):
+        """Get the position of an entry or return -1"""
+        if isinstance(key, basestring):
+            for idx, value in enumerate(self):
+                if value[0] == key:
+                    return idx
+            return -1
+        return list.find(self, key)
+
+    def values(self):
+        """Return a list of the values, not the qualities."""
+        return [x[0] for x in self]
+
+    def itervalues(self):
+        """Iterate over all values."""
+        for item in self:
+            yield item[0]
+
+    def best(self):
+        """The best match as value."""
+        return self and self[0][0] or None
+    best = property(best)
+
+
+class HeaderSet(object):
+    """Similar to the `ETags` class this implements a set like structure.
+    Unlike `ETags` this is case insensitive and used for vary, allow, and
+    content-language headers.
+
+    If not constructed using the `parse_set_header` function the instanciation
+    works like this:
+
+    >>> hs = HeaderSet(['foo', 'bar', 'baz'])
+    >>> hs
+    HeaderSet(['foo', 'bar', 'baz'])
+    """
+
+    def __init__(self, headers=None, on_update=None):
+        self._headers = list(headers or ())
+        self._set = set([x.lower() for x in self._headers])
+        self.on_update = on_update
+
+    def add(self, header):
+        """Add a new header to the set."""
+        self.update((header,))
+
+    def remove(self, header):
+        """Remove a layer from the set.  This raises an `IndexError` if the
+        header is not in the set."""
+        key = header.lower()
+        if key not in self._set:
+            raise IndexError(header)
+        self._set.remove(key)
+        for idx, key in enumerate(self._headers):
+            if key.lower() == header:
+                del self._headers[idx]
+                break
+        if self.on_update is not None:
+            self.on_update(self)
+
+    def update(self, iterable):
+        """Add all the headers from the iterable to the set."""
+        inserted_any = False
+        for header in iterable:
+            key = header.lower()
+            if key not in self._set:
+                self._headers.append(header)
+                self._set.add(key)
+                inserted_any = True
+        if inserted_any and self.on_update is not None:
+            self.on_update(self)
+
+    def discard(self, header):
+        """Like remove but ignores errors."""
+        try:
+            return self.remove(header)
+        except IndexError:
+            pass
+
+    def find(self, header):
+        """Return the index of the header in the set or return -1 if not found."""
+        header = header.lower()
+        for idx, item in enumerate(self._headers):
+            if item.lower() == header:
+                return idx
+        return -1
+
+    def index(self, header):
+        """Return the index of the headerin the set or raise an `IndexError`."""
+        rv = self.find(header)
+        if rv < 0:
+            raise IndexError(header)
+        return rv
+
+    def clear(self):
+        """Clear the set."""
+        self._set.clear()
+        del self._headers[:]
+        if self.on_update is not None:
+            self.on_update(self)
+
+    def as_set(self, preserve_casing=False):
+        """Return the set as real python set structure.  When calling this
+        all the items are converted to lowercase and the ordering is lost.
+
+        If `preserve_casing` is `True` the items in the set returned will
+        have the original case like in the `HeaderSet`, otherwise they will
+        be lowercase.
+        """
+        if preserve_casing:
+            return set(self._headers)
+        return set(self._set)
+
+    def to_header(self):
+        """Convert the header set into an HTTP header string."""
+        return ', '.join(map(quote_header_value, self._headers))
+
+    def __getitem__(self, idx):
+        return self._headers[idx]
+
+    def __delitem__(self, idx):
+        rv = self._headers.pop(idx)
+        self._set.remove(rv.lower())
+        if self.on_update is not None:
+            self.on_update(self)
+
+    def __setitem__(self, idx, value):
+        old = self._headers[idx]
+        self._set.remove(old.lower())
+        self._headers[idx] = value
+        self._set.add(value.lower())
+        if self.on_update is not None:
+            self.on_update(self)
+
+    def __contains__(self, header):
+        return header.lower() in self._set
+
+    def __len__(self):
+        return len(self._set)
+
+    def __iter__(self):
+        return iter(self._headers)
+
+    def __nonzero__(self):
+        return bool(self._set)
+
+    def __str__(self):
+        return self.to_header()
+
+    def __repr__(self):
+        return '%s(%r)' % (
+            self.__class__.__name__,
+            self._headers
+        )
+
+
+class CacheControl(_UpdateDict):
+    """Subclass of a dict that stores values for a Cache-Control header.  It
+    has accesors for all the cache-control directives specified in RFC 2616.
+    The class does not differentiate between request and response directives.
+
+    Because the cache-control directives in the HTTP header use dashes the
+    python descriptors use underscores for that.
+
+    To get a header of the `CacheControl` object again you can convert the
+    object into a string or call the `to_header()` function.  If you plan
+    to subclass it and add your own items have a look at the sourcecode for
+    that class.
+
+    The following attributes are exposed:
+
+    `no_cache`, `no_store`, `max_age`, `max_stale`, `min_fresh`,
+    `no_transform`, `only_if_cached`, `public`, `private`, `must_revalidate`,
+    `proxy_revalidate`, and `s_maxage`"""
+
+    def cache_property(key, default, type):
+        """Return a new property object for a cache header.  Useful if you
+        want to add support for a cache extension in a subclass."""
+        return property(lambda x: x._get_cache_value(key, default, type),
+                        lambda x, v: x._set_cache_value(key, v, type),
+                        'accessor for %r' % key)
+
+    no_cache = cache_property('no-cache', '*', bool)
+    no_store = cache_property('no-store', None, bool)
+    max_age = cache_property('max-age', -1, int)
+    max_stale = cache_property('max-stale', '*', int)
+    min_fresh = cache_property('min-fresh', '*', int)
+    no_transform = cache_property('no-transform', None, None)
+    only_if_cached = cache_property('only-if-cached', None, bool)
+    public = cache_property('public', None, bool)
+    private = cache_property('private', '*', None)
+    must_revalidate = cache_property('must-revalidate', None, bool)
+    proxy_revalidate = cache_property('proxy-revalidate', None, bool)
+    s_maxage = cache_property('s-maxage', None, None)
+
+    def __init__(self, values=(), on_update=None):
+        _UpdateDict.__init__(self, values or (), on_update)
+        self.provided = values is not None
+
+    def _get_cache_value(self, key, default, type):
+        """Used internally be the accessor properties."""
+        if type is bool:
+            return key in self
+        if key in self:
+            value = self[key]
+            if value is None:
+                return default
+            elif type is not None:
+                try:
+                    value = type(value)
+                except ValueError:
+                    pass
+            return value
+
+    def _set_cache_value(self, key, value, type):
+        """Used internally be the accessor properties."""
+        if type is bool:
+            if value:
+                self[key] = None
+            else:
+                self.pop(key, None)
+        else:
+            if value is not None:
+                self[key] = value
+            else:
+                self.pop(key, None)
+
+    def to_header(self):
+        """Convert the stored values into a cache control header."""
+        return dump_header(self)
+
+    def __str__(self):
+        return self.to_header()
+
+    def __repr__(self):
+        return '<%s %r>' % (
+            self.__class__.__name__,
+            self.to_header()
+        )
+
+    # make cache_property a staticmethod so that subclasses of
+    # `CacheControl` can use it for new properties.
+    cache_property = staticmethod(cache_property)
+
+
+class ETags(object):
+    """A set that can be used to check if one etag is present in a collection
+    of etags.
+    """
+
+    def __init__(self, strong_etags=None, weak_etags=None, star_tag=False):
+        self._strong = frozenset(not star_tag and strong_etags or ())
+        self._weak = frozenset(weak_etags or ())
+        self.star_tag = star_tag
+
+    def as_set(self, include_weak=False):
+        """Convert the `ETags` object into a python set.  Per default all the
+        weak etags are not part of this set."""
+        rv = set(self._strong)
+        if include_weak:
+            rv.update(self._weak)
+        return rv
+
+    def is_weak(self, etag):
+        """Check if an etag is weak."""
+        return etag in self._weak
+
+    def contains_weak(self, etag):
+        """Check if an etag is part of the set including weak and strong tags."""
+        return self.is_weak(etag) or self.contains(etag)
+
+    def contains(self, etag):
+        """Check if an etag is part of the set ignoring weak tags."""
+        if self.star_tag:
+            return True
+        return etag in self._strong
+
+    def contains_raw(self, etag):
+        """When passed a quoted tag it will check if this tag is part of the
+        set.  If the tag is weak it is checked against weak and strong tags,
+        otherwise weak only."""
+        etag, weak = unquote_etag(etag)
+        if weak:
+            return self.contains_weak(etag)
+        return self.contains(etag)
+
+    def to_header(self):
+        """Convert the etags set into a HTTP header string."""
+        if self.star_tag:
+            return '*'
+        return ', '.join(
+            ['"%s"' % x for x in self._strong] +
+            ['w/"%s"' % x for x in self._weak]
+        )
+
+    def __call__(self, etag=None, data=None, include_weak=False):
+        if [etag, data].count(None) != 1:
+            raise TypeError('either tag or data required, but at least one')
+        if etag is None:
+            etag = generate_etag(data)
+        if include_weak:
+            if etag in self._weak:
+                return True
+        return etag in self._strong
+
+    def __nonzero__(self):
+        return bool(self.star_tag or self._strong)
+
+    def __str__(self):
+        return self.to_header()
+
+    def __iter__(self):
+        return iter(self._strong)
+
+    def __contains__(self, etag):
+        return self.contains(etag)
+
+    def __repr__(self):
+        return '<%s %r>' % (self.__class__.__name__, str(self))
+
+
+class Authorization(dict):
+    """Represents an `Authorization` header sent by the client.  You should
+    not create this kind of object yourself but use it when it's returned by
+    the `parse_authorization_header` function.
+
+    This object is a dict subclass and can be altered by setting dict items
+    but it should be considered immutable as it's returned by the client and
+    not meant for modifications.
+    """
+
+    def __init__(self, auth_type, data=None):
+        dict.__init__(self, data or {})
+        self.type = auth_type
+
+    username = property(lambda x: x.get('username'), doc='''
+        The username transmitted.  This is set for both basic and digest
+        auth all the time.''')
+    password = property(lambda x: x.get('password'), doc='''
+        When the authentication type is basic this is the password
+        transmitted by the client, else `None`.''')
+    realm = property(lambda x: x.get('realm'), doc='''
+        This is the server realm send back for digest auth.  For HTTP
+        digest auth.''')
+    nonce = property(lambda x: x.get('nonce'), doc='''
+        The nonce the server send for digest auth, send back by the client.
+        A nonce should be unique for every 401 response for HTTP digest
+        auth.''')
+    uri = property(lambda x: x.get('uri'), doc='''
+        The URI from Request-URI of the Request-Line; duplicated because
+        proxies are allowed to change the Request-Line in transit.  HTTP
+        digest auth only.''')
+    nc = property(lambda x: x.get('nc'), doc='''
+        The nonce count value transmitted by clients if a qop-header is
+        also transmitted.  HTTP digest auth only.''')
+    cnonce = property(lambda x: x.get('cnonce'), doc='''
+        If the server sent a qop-header in the ``WWW-Authenticate``
+        header, the client has to provide this value for HTTP digest auth.
+        See the RFC for more details.''')
+    response = property(lambda x: x.get('response'), doc='''
+        A string of 32 hex digits computed as defined in RFC 2617, which
+        proves that the user knows a password.  Digest auth only.''')
+    opaque = property(lambda x: x.get('opaque'), doc='''
+        The opaque header from the server returned unchanged by the client.
+        It is recommended that this string be base64 or hexadecimal data.
+        Digest auth only.''')
+
+    def qop(self):
+        """Indicates what "quality of protection" the client has applied to
+        the message for HTTP digest auth."""
+        def on_update(header_set):
+            if not header_set and name in self:
+                del self['qop']
+            elif header_set:
+                self['qop'] = header_set.to_header()
+        return parse_set_header(self.get('qop'), on_update)
+    qop = property(qop, doc=qop.__doc__)
+
+
+class WWWAuthenticate(_UpdateDict):
+    """Provides simple access to `WWW-Authenticate` headers."""
+
+    #: list of keys that require quoting in the generated header
+    _require_quoting = frozenset(['domain', 'nonce', 'opaque', 'realm'])
+
+    def __init__(self, auth_type=None, values=None, on_update=None):
+        _UpdateDict.__init__(self, values or (), on_update)
+        if auth_type:
+            self['__auth_type__'] = auth_type
+
+    def set_basic(self, realm='authentication required'):
+        """Clear the auth info and enable basic auth."""
+        dict.clear(self)
+        dict.update(self, {'__auth_type__': 'basic', 'realm': realm})
+        if self.on_update:
+            self.on_update(self)
+
+    def set_digest(self, realm, nonce, qop=('auth',), opaque=None,
+                   algorithm=None, stale=False):
+        """Clear the auth info and enable digest auth."""
+        d = {
+            '__auth_type__':    'digest',
+            'realm':            realm,
+            'nonce':            nonce,
+            'qop':              dump_header(qop)
+        }
+        if stale:
+            d['stale'] = 'TRUE'
+        if opaque is not None:
+            d['opaque'] = opaque
+        if algorithm is not None:
+            d['algorithm'] = algorithm
+        dict.clear(self)
+        dict.update(self, d)
+        if self.on_update:
+            self.on_update(self)
+
+    def to_header(self):
+        """Convert the stored values into a WWW-Authenticate header."""
+        d = dict(self)
+        auth_type = d.pop('__auth_type__', None) or 'basic'
+        return '%s %s' % (auth_type.title(), ', '.join([
+            '%s=%s' % (key, quote_header_value(value,
+                       allow_token=key not in self._require_quoting))
+            for key, value in d.iteritems()
+        ]))
+
+    def __str__(self):
+        return self.to_header()
+
+    def __repr__(self):
+        return '<%s %r>' % (
+            self.__class__.__name__,
+            self.to_header()
+        )
+
+    def auth_property(name, doc=None):
+        def _set_value(self, value):
+            if value is None:
+                self.pop(name, None)
+            else:
+                self[name] = str(value)
+        return property(lambda x: x.get(name), _set_value, doc=doc)
+
+    def _set_property(name, doc=None):
+        def fget(self):
+            def on_update(header_set):
+                if not header_set and name in self:
+                    del self[name]
+                elif header_set:
+                    self[name] = header_set.to_header()
+            return parse_set_header(self.get(name), on_update)
+        return property(fget, doc=doc)
+
+    type = auth_property('__auth_type__', doc='''
+        The type of the auth machanism.  HTTP currently specifies
+        `Basic` and `Digest`.''')
+    realm = auth_property('realm', doc='''
+        A string to be displayed to users so they know which username and
+        password to use.  This string should contain at least the name of
+        the host performing the authentication and might additionally
+        indicate the collection of users who might have access.''')
+    domain = _set_property('domain', doc='''
+        A list of URIs that define the protection space.  If a URI is an
+        absolte path, it is relative to the canonical root URL of the
+        server being accessed.''')
+    nonce = auth_property('nonce', doc='''
+        A server-specified data string which should be uniquely generated
+        each time a 401 response is made.  It is recommended that this
+        string be base64 or hexadecimal data.''')
+    opaque = auth_property('opaque', doc='''
+        A string of data, specified by the server, which should be returned
+        by the client unchanged in the Authorization header of subsequent
+        requests with URIs in the same protection space.  It is recommended
+        that this string be base64 or hexadecimal data.''')
+    algorithm = auth_property('algorithm', doc='''
+        A string indicating a pair of algorithms used to produce the digest
+        and a checksum.  If this is not present it is assumed to be "MD5".
+        If the algorithm is not understood, the challenge should be ignored
+        (and a different one used, if there is more than one).''')
+    qop = _set_property('qop', doc='''
+        A set of quality-of-privacy modifies such as auth and auth-int.''')
+
+    def _get_stale(self):
+        val = self.get('stale')
+        if val is not None:
+            return val.lower() == 'true'
+    def _set_stale(self, value):
+        if value is None:
+            self.pop('stale', None)
+        else:
+            self['stale'] = value and 'TRUE' or 'FALSE'
+    stale = property(_get_stale, _set_stale, doc='''
+        A flag, indicating that the previous request from the client was
+        rejected because the nonce value was stale.''')
+    del _get_stale, _set_stale
+
+    # make auth_property a staticmethod so that subclasses of
+    # `WWWAuthenticate` can use it for new properties.
+    auth_property = staticmethod(auth_property)
+    del _set_property
+
+
+def quote_header_value(value, extra_chars='', allow_token=True):
+    """Quote a header value if necessary."""
+    value = str(value)
+    if allow_token:
+        token_chars = _token_chars | set(extra_chars)
+        if set(value).issubset(token_chars):
+            return value
+    return '"%s"' % value.replace('\\', '\\\\').replace('"', '\\"')
+
+
+def dump_header(iterable, allow_token=True):
+    """Dump an HTTP header again.  This is the reversal of
+    `parse_list_header`, `parse_set_header` and `parse_dict_header`.  This
+    also quotes strings that include an equals sign unless you pass it as dict
+    of key, value pairs.
+
+    The `allow_token` parameter can be set to `False` to disallow tokens as
+    values.  If this is enabled all values are quoted.
+    """
+    if isinstance(iterable, dict):
+        items = []
+        for key, value in iterable.iteritems():
+            if value is None:
+                items.append(key)
+            else:
+                items.append('%s=%s' % (
+                    key,
+                    quote_header_value(value, allow_token=allow_token)
+                ))
+    else:
+        items = [quote_header_value(x, allow_token=allow_token)
+                 for x in iterable]
+    return ', '.join(items)
+
+
+def parse_list_header(value):
+    """Parse lists as described by RFC 2068 Section 2.
+
+    In particular, parse comma-separated lists where the elements of
+    the list may include quoted-strings.  A quoted-string could
+    contain a comma.  A non-quoted string could have quotes in the
+    middle.  Quotes are removed automatically after parsing.
+    """
+    result = []
+    for item in _parse_list_header(value):
+        if item[:1] == item[-1:] == '"':
+            item = item[1:-1]
+        result.append(item)
+    return result
+
+
+def parse_dict_header(value):
+    """Parse lists of key, value paits as described by RFC 2068 Section 2 and
+    convert them into a python dict.  If there is no value for a key it will
+    be `None`.
+    """
+    result = {}
+    for item in _parse_list_header(value):
+        if '=' not in item:
+            result[item] = None
+            continue
+        name, value = item.split('=', 1)
+        if value[:1] == value[-1:] == '"':
+            value = value[1:-1]
+        result[name] = value
+    return result
+
+
+def parse_accept_header(value):
+    """Parses an HTTP Accept-* header.  This does not implement a complete
+    valid algorithm but one that supports at least value and quality
+    extraction.
+
+    Returns a new `Accept` object (basicly a list of ``(value, quality)``
+    tuples sorted by the quality with some additional accessor methods).
+    """
+    if not value:
+        return Accept(None)
+    result = []
+    for match in _accept_re.finditer(value):
+        quality = match.group(2)
+        if not quality:
+            quality = 1
+        else:
+            quality = max(min(float(quality), 1), 0)
+        result.append((match.group(1), quality))
+    return Accept(result)
+
+
+def parse_cache_control_header(value, on_update=None):
+    """Parse a cache control header.  The RFC differs between response and
+    request cache control, this method does not.  It's your responsibility
+    to not use the wrong control statements.
+    """
+    if not value:
+        return CacheControl(None, on_update)
+    return CacheControl(parse_dict_header(value), on_update)
+
+
+def parse_set_header(value, on_update=None):
+    """Parse a set like header and return a `HeaderSet` object.  The return
+    value is an object that treats the items case insensitive and keeps the
+    order of the items.
+    """
+    if not value:
+        return HeaderSet(None, on_update)
+    return HeaderSet(parse_list_header(value), on_update)
+
+
+def parse_authorization_header(value):
+    """Parse an HTTP basic/digest authorization header transmitted by the web
+    browser.  The return value is either `None` if the header was invalid or
+    not given, otherwise an `Authorization` object.
+    """
+    if not value:
+        return
+    try:
+        auth_type, auth_info = value.split(None, 1)
+        auth_type = auth_type.lower()
+    except ValueError:
+        return
+    if auth_type == 'basic':
+        try:
+            username, password = auth_info.decode('base64').split(':', 1)
+        except Exception, e:
+            return
+        return Authorization('basic', {'username': username,
+                                       'password': password})
+    elif auth_type == 'digest':
+        auth_map = parse_dict_header(auth_info)
+        for key in 'username', 'realm', 'nonce', 'uri', 'nc', 'cnonce', \
+                   'response':
+            if not key in auth_map:
+                return
+        return Authorization('digest', auth_map)
+
+
+def parse_www_authenticate_header(value, on_update=None):
+    """Parse an HTTP WWW-Authenticate header into a `WWWAuthenticate`
+    object."""
+    if not value:
+        return WWWAuthenticate(on_update=on_update)
+    try:
+        auth_type, auth_info = value.split(None, 1)
+        auth_type = auth_type.lower()
+    except (ValueError, AttributeError):
+        return WWWAuthenticate(value.lower(), on_update=on_update)
+    return WWWAuthenticate(auth_type, parse_dict_header(auth_info),
+                           on_update)
+
+
+def quote_etag(etag, weak=False):
+    """Quote an etag."""
+    if '"' in etag:
+        raise ValueError('invalid etag')
+    etag = '"%s"' % etag
+    if weak:
+        etag = 'w/' + etag
+    return etag
+
+
+def unquote_etag(etag):
+    """Unquote a single etag.  Return a ``(etag, weak)`` tuple."""
+    if not etag:
+        return None, None
+    etag = etag.strip()
+    weak = False
+    if etag[:2] in ('w/', 'W/'):
+        weak = True
+        etag = etag[2:]
+    if etag[:1] == etag[-1:] == '"':
+        etag = etag[1:-1]
+    return etag, weak
+
+
+def parse_etags(value):
+    """Parse and etag header.  Returns an `ETags` object."""
+    if not value:
+        return ETags()
+    strong = []
+    weak = []
+    end = len(value)
+    pos = 0
+    while pos < end:
+        match = _etag_re.match(value, pos)
+        if match is None:
+            break
+        is_weak, quoted, raw = match.groups()
+        if raw == '*':
+            return ETags(star_tag=True)
+        elif quoted:
+            raw = quoted
+        if is_weak:
+            weak.append(raw)
+        else:
+            strong.append(raw)
+        pos = match.end()
+    return ETags(strong, weak)
+
+
+def generate_etag(data):
+    """Generate an etag for some data."""
+    return md5(data).hexdigest()
+
+
+def parse_date(value):
+    """Parse one of the following date formats into a datetime object:
+
+    .. sourcecode:: text
+
+        Sun, 06 Nov 1994 08:49:37 GMT  ; RFC 822, updated by RFC 1123
+        Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
+        Sun Nov  6 08:49:37 1994       ; ANSI C's asctime() format
+
+    If parsing fails the return value is `None`.
+    """
+    if value:
+        t = rfc822.parsedate_tz(value.strip())
+        if t is not None:
+            # if no timezone is part of the string we assume UTC
+            if t[-1] is None:
+                t = t[:-1] + (0,)
+            return datetime.utcfromtimestamp(rfc822.mktime_tz(t))
+
+
+def is_resource_modified(environ, etag=None, data=None, last_modified=None):
+    """Convenience method for conditional requests."""
+    if etag is None and data is not None:
+        etag = generate_etag(data)
+    elif data is not None:
+        raise TypeError('both data and etag given')
+    if environ['REQUEST_METHOD'] not in ('GET', 'HEAD'):
+        return False
+
+    unmodified = False
+    if isinstance(last_modified, basestring):
+        last_modified = parse_date(last_modified)
+    modified_since = parse_date(environ.get('HTTP_IF_MODIFIED_SINCE'))
+
+    if modified_since and last_modified and last_modified <= modified_since:
+        unmodified = True
+    if etag:
+        if_none_match = parse_etags(environ.get('HTTP_IF_NONE_MATCH'))
+        if if_none_match:
+            unmodified = if_none_match.contains_raw(etag)
+
+    return not unmodified
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/local.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,328 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.local
+    ~~~~~~~~~~~~~~
+
+    Sooner or later you have some things you want to have in every single view
+    or helper function or whatever.  In PHP the way to go are global
+    variables.  However that is not possible in WSGI applications without a
+    major drawback:  As soon as you operate on the global namespace your
+    application is not thread safe any longer.
+
+    The python standard library comes with a utility called "thread locals".
+    A thread local is a global object where you can put stuff on and get back
+    later in a thread safe way.  That means whenever you set or get an object
+    to / from a thread local object the thread local object checks in which
+    thread you are and delivers the correct value.
+
+    This however has a few disadvantages.  For example beside threads there
+    are other ways to handle concurrency in Python.  A very popular approach
+    are greenlets.  Also, whether every request gets its own thread is not
+    guaranteed in WSGI.  It could be that a request is reusing a thread from
+    before and data is left in the thread local object.
+
+
+    Nutshell
+    --------
+
+    Here a simple example how you can use werkzeug.local::
+
+        from werkzeug import Local, LocalManager
+
+        local = Local()
+        local_manager = LocalManager([local])
+
+        def application(environ, start_response):
+            local.request = request = Request(environ)
+            ...
+
+        application = local_manager.make_middleware(application)
+
+    Now what this code does is binding request to `local.request`.  Every
+    other piece of code executed after this assignment in the same context can
+    safely access local.request and will get the same request object.  The
+    `make_middleware` method on the local manager ensures that everything is
+    cleaned up after the request.
+
+    The same context means the same greenlet (if you're using greenlets) in
+    the same thread and same process.
+
+    If a request object is not yet set on the local object and you try to
+    access it you will get an `AttributeError`.  You can use `getattr` to avoid
+    that::
+
+        def get_request():
+            return getattr(local, 'request', None)
+
+    This will try to get the request or return `None` if the request is not
+    (yet?) available.
+
+    Note that local objects cannot manage themselves, for that you need a local
+    manager.  You can pass a local manager multiple locals or add additionals
+    later by appending them to `manager.locals` and everytime the manager
+    cleans up it will clean up all the data left in the locals for this
+    context.
+
+
+    :copyright: 2007-2008 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+try:
+    from py.magic import greenlet
+    get_current_greenlet = greenlet.getcurrent
+    del greenlet
+except (RuntimeError, ImportError):
+    get_current_greenlet = int
+try:
+    from thread import get_ident as get_current_thread, allocate_lock
+except ImportError:
+    from dummy_thread import get_ident as get_current_thread, allocate_lock
+from werkzeug.utils import ClosingIterator
+from werkzeug._internal import _patch_wrapper
+
+
+# get the best ident function.  if greenlets are not installed we can
+# savely just use the builtin thread function and save a python methodcall
+# and the cost of caculating a hash.
+if get_current_greenlet is int:
+    get_ident = get_current_thread
+else:
+    get_ident = lambda: hash((get_current_thread(), get_current_greenlet()))
+
+
+class Local(object):
+    __slots__ = ('__storage__', '__lock__')
+
+    def __init__(self):
+        object.__setattr__(self, '__storage__', {})
+        object.__setattr__(self, '__lock__', allocate_lock())
+
+    def __iter__(self):
+        return self.__storage__.iteritems()
+
+    def __call__(self, proxy):
+        """Create a proxy for a name."""
+        return LocalProxy(self, proxy)
+
+    def __getattr__(self, name):
+        self.__lock__.acquire()
+        try:
+            try:
+                return self.__storage__[get_ident()][name]
+            except KeyError:
+                raise AttributeError(name)
+        finally:
+            self.__lock__.release()
+
+    def __setattr__(self, name, value):
+        self.__lock__.acquire()
+        try:
+            ident = get_ident()
+            storage = self.__storage__
+            if ident in storage:
+                storage[ident][name] = value
+            else:
+                storage[ident] = {name: value}
+        finally:
+            self.__lock__.release()
+
+    def __delattr__(self, name):
+        self.__lock__.acquire()
+        try:
+            try:
+                del self.__storage__[get_ident()][name]
+            except KeyError:
+                raise AttributeError(name)
+        finally:
+            self.__lock__.release()
+
+
+class LocalManager(object):
+    """Local objects cannot manage themselves. For that you need a local
+    manager.  You can pass a local manager multiple locals or add them later
+    by appending them to `manager.locals`.  Everytime the manager cleans up
+    it, will clean up all the data left in the locals for this context.
+    """
+
+    def __init__(self, locals=None):
+        if locals is None:
+            self.locals = []
+        else:
+            try:
+                self.locals = list(locals)
+            except TypeError:
+                self.locals = [locals]
+
+    def get_ident(self):
+        """Return the context identifier the local objects use internally for
+        this context.  You cannot override this method to change the behavior
+        but use it to link other context local objects (such as SQLAlchemy's
+        scoped sessions) to the Werkzeug locals.
+        """
+        return get_ident()
+
+    def cleanup(self):
+        """Manually clean up the data in the locals for this context.  Call
+        this at the end of the request or use `make_middleware()`.
+        """
+        ident = self.get_ident()
+        for local in self.locals:
+            local.__storage__.pop(ident, None)
+
+    def make_middleware(self, app):
+        """Wrap a WSGI application so that cleaning up happens after
+        request end.
+        """
+        def application(environ, start_response):
+            return ClosingIterator(app(environ, start_response), self.cleanup)
+        return application
+
+    def middleware(self, func):
+        """Like `make_middleware` but for decorating functions.
+
+        Example usage::
+
+            @manager.middleware
+            def application(environ, start_response):
+                ...
+
+        The difference to `make_middleware` is that the function passed
+        will have all the arguments copied from the inner application
+        (name, docstring, module).
+        """
+        return _patch_wrapper(func, self.make_middleware(func))
+
+    def __repr__(self):
+        return '<%s storages: %d>' % (
+            self.__class__.__name__,
+            len(self.locals)
+        )
+
+
+class LocalProxy(object):
+    """Acts as a proxy for a werkzeug local.  Forwards all operations to
+    a proxied object.  The only operations not supported for forwarding
+    are right handed operands and any kind of assignment.
+
+    Example usage::
+
+        from werkzeug import Local
+        l = Local()
+        request = l('request')
+        user = l('user')
+
+    Whenever something is bound to l.user / l.request the proxy objects
+    will forward all operations.  If no object is bound a `RuntimeError`
+    will be raised.
+    """
+    __slots__ = ('__local', '__dict__', '__name__')
+
+    def __init__(self, local, name):
+        object.__setattr__(self, '_LocalProxy__local', local)
+        object.__setattr__(self, '__name__', name)
+
+    def _get_current_object(self):
+        """Return the current object.  This is useful if you want the real
+        object behind the proxy at a time for performance reasons or because
+        you want to pass the object into a different context.
+        """
+        try:
+            return getattr(self.__local, self.__name__)
+        except AttributeError:
+            raise RuntimeError('no object bound to %s' % self.__name__)
+    __current_object = property(_get_current_object)
+
+    def __dict__(self):
+        try:
+            return self.__current_object.__dict__
+        except RuntimeError:
+            return AttributeError('__dict__')
+    __dict__ = property(__dict__)
+
+    def __repr__(self):
+        try:
+            obj = self.__current_object
+        except RuntimeError:
+            return '<%s unbound>' % self.__class__.__name__
+        return repr(obj)
+
+    def __nonzero__(self):
+        try:
+            return bool(self.__current_object)
+        except RuntimeError:
+            return False
+
+    def __unicode__(self):
+        try:
+            return unicode(self.__current_oject)
+        except RuntimeError:
+            return repr(self)
+
+    def __dir__(self):
+        try:
+            return dir(self.__current_object)
+        except RuntimeError:
+            return []
+
+    def __getattr__(self, name):
+        if name == '__members__':
+            return dir(self.__current_object)
+        return getattr(self.__current_object, name)
+
+    def __setitem__(self, key, value):
+        self.__current_object[key] = value
+
+    def __delitem__(self, key):
+        del self.__current_object[key]
+
+    def __setslice__(self, i, j, seq):
+        self.__current_object[i:j] = seq
+
+    def __delslice__(self, i, j):
+        del self.__current_object[i:j]
+
+    __setattr__ = lambda x, n, v: setattr(x.__current_object, n, v)
+    __delattr__ = lambda x, n: delattr(x.__current_object, n)
+    __str__ = lambda x: str(x.__current_object)
+    __lt__ = lambda x, o: x.__current_object < o
+    __le__ = lambda x, o: x.__current_object <= o
+    __eq__ = lambda x, o: x.__current_object == o
+    __ne__ = lambda x, o: x.__current_object != o
+    __gt__ = lambda x, o: x.__current_object > o
+    __ge__ = lambda x, o: x.__current_object >= o
+    __cmp__ = lambda x, o: cmp(x.__current_object, o)
+    __hash__ = lambda x: hash(x.__current_object)
+    __call__ = lambda x, *a, **kw: x.__current_object(*a, **kw)
+    __len__ = lambda x: len(x.__current_object)
+    __getitem__ = lambda x, i: x.__current_object[i]
+    __iter__ = lambda x: iter(x.__current_object)
+    __contains__ = lambda x, i: i in x.__current_object
+    __getslice__ = lambda x, i, j: x.__current_object[i:j]
+    __add__ = lambda x, o: x.__current_object + o
+    __sub__ = lambda x, o: x.__current_object - o
+    __mul__ = lambda x, o: x.__current_object * o
+    __floordiv__ = lambda x, o: x.__current_object // o
+    __mod__ = lambda x, o: x.__current_object % o
+    __divmod__ = lambda x, o: x.__current_object.__divmod__(o)
+    __pow__ = lambda x, o: x.__current_object ** o
+    __lshift__ = lambda x, o: x.__current_object << o
+    __rshift__ = lambda x, o: x.__current_object >> o
+    __and__ = lambda x, o: x.__current_object & o
+    __xor__ = lambda x, o: x.__current_object ^ o
+    __or__ = lambda x, o: x.__current_object | o
+    __div__ = lambda x, o: x.__current_object.__div__(o)
+    __truediv__ = lambda x, o: x.__current_object.__truediv__(o)
+    __neg__ = lambda x: -(x.__current_object)
+    __pos__ = lambda x: +(x.__current_object)
+    __abs__ = lambda x: abs(x.__current_object)
+    __invert__ = lambda x: ~(x.__current_object)
+    __complex__ = lambda x: complex(x.__current_object)
+    __int__ = lambda x: int(x.__current_object)
+    __long__ = lambda x: long(x.__current_object)
+    __float__ = lambda x: float(x.__current_object)
+    __oct__ = lambda x: oct(x.__current_object)
+    __hex__ = lambda x: hex(x.__current_object)
+    __index__ = lambda x: x.__current_object.__index__()
+    __coerce__ = lambda x, o: x.__coerce__(x, o)
+    __enter__ = lambda x: x.__enter__()
+    __exit__ = lambda x, *a, **kw: x.__exit__(*a, **kw)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/routing.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,1283 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.routing
+    ~~~~~~~~~~~~~~~~
+
+    When it comes to combining multiple controller or view functions (however
+    you want to call them) you need a dispatcher.  A simple way would be
+    applying regular expression tests on the ``PATH_INFO`` and call registered
+    callback functions that return the value then.
+
+    This module implements a much more powerful system than simple regular
+    expression matching because it can also convert values in the URLs and
+    build URLs.
+
+    Here a simple example that creates an URL map for an application with
+    two subdomains (www and kb) and some URL rules::
+
+        m = Map([
+            # Static URLs
+            Rule('/', endpoint='static/index'),
+            Rule('/about', endpoint='static/about'),
+            Rule('/help', endpoint='static/help'),
+
+            # Knowledge Base
+            Subdomain('kb', [
+                Rule('/', endpoint='kb/index'),
+                Rule('/browse/', endpoint='kb/browse'),
+                Rule('/browse/<int:id>/', endpoint='kb/browse'),
+                Rule('/browse/<int:id>/<int:page>', endpoint='kb/browse')
+            ])
+        ], default_subdomain='www')
+
+    If the application doesn't use subdomains it's perfectly fine to not set
+    the default subdomain and use the `Subdomain` rule factory.  The endpoint
+    in the rules can be anything, for example import paths or unique
+    identifiers.  The WSGI application can use those endpoints to get the
+    handler for that URL.  It doesn't have to be a string at all but it's
+    recommended.
+
+    Now it's possible to create a URL adapter for one of the subdomains and
+    build URLs:
+
+    >>> c = m.bind('example.com')
+    >>> c.build("kb/browse", dict(id=42))
+    'http://kb.example.com/browse/42/'
+    >>> c.build("kb/browse", dict())
+    'http://kb.example.com/browse/'
+    >>> c.build("kb/browse", dict(id=42, page=3))
+    'http://kb.example.com/browse/42/3'
+    >>> c.build("static/about")
+    u'/about'
+    >>> c.build("static/about", subdomain="kb")
+    'http://www.example.com/about'
+    >>> c.build("static/index", force_external=True)
+    'http://www.example.com/'
+
+    The first argument to bind is the server name *without* the subdomain.
+    Per default it will assume that the script is mounted on the root, but
+    often that's not the case so you can provide the real mount point as
+    second argument:
+
+    >>> c = m.bind('example.com', '/applications/example')
+
+    The third argument can be the subdomain, if not given the default
+    subdomain is used.  For more details about binding have a look at the
+    documentation of the `MapAdapter`.
+
+    And here is how you can match URLs:
+
+    >>> c = m.bind('example.com')
+    >>> c.match("/")
+    ('static/index', {})
+    >>> c.match("/about")
+    ('static/about', {})
+    >>> c = m.bind('example.com', '/', 'kb')
+    >>> c.match("/")
+    ('kb/index', {})
+    >>> c.match("/browse/42/23")
+    ('kb/browse', {'id': 42, 'page': 23})
+
+    If matching fails you get a `NotFound` exception, if the rule thinks
+    it's a good idea to redirect (for example because the URL was defined
+    to have a slash at the end but the request was missing that slash) it
+    will raise a `RequestRedirect` exception.  Both are subclasses of the
+    `HTTPException` so you can use those errors as responses in the
+    application.
+
+    If matching succeeded but the URL rule was incompatible to the given
+    method (for example there were only rules for `GET` and `HEAD` and
+    routing system tried to match a `POST` request) a `MethodNotAllowed`
+    method is raised.
+
+
+    :copyright: 2007-2008 by Armin Ronacher, Leif K-Brooks,
+                             Thomas Johansson.
+    :license: BSD, see LICENSE for more details.
+"""
+import sys
+import re
+from urlparse import urljoin
+from itertools import izip
+
+from werkzeug.utils import url_encode, url_quote, redirect, format_string
+from werkzeug.exceptions import HTTPException, NotFound, MethodNotAllowed
+try:
+    set
+except NameError:
+    from sets import Set as set
+
+
+_rule_re = re.compile(r'''
+    (?P<static>[^<]*)                           # static rule data
+    <
+    (?:
+        (?P<converter>[a-zA-Z_][a-zA-Z0-9_]*)   # converter name
+        (?:\((?P<args>.*?)\))?                  # converter arguments
+        \:                                      # variable delimiter
+    )?
+    (?P<variable>[a-zA-Z][a-zA-Z0-9_]*)         # variable name
+    >
+''', re.VERBOSE)
+_simple_rule_re = re.compile(r'<([^>]+)>')
+
+
+def parse_rule(rule):
+    """Parse a rule and return it as generator. Each iteration yields tuples
+    in the form ``(converter, arguments, variable)``. If the converter is
+    `None` it's a static url part, otherwise it's a dynamic one.
+
+    :internal:
+    """
+    pos = 0
+    end = len(rule)
+    do_match = _rule_re.match
+    used_names = set()
+    while pos < end:
+        m = do_match(rule, pos)
+        if m is None:
+            break
+        data = m.groupdict()
+        if data['static']:
+            yield None, None, data['static']
+        variable = data['variable']
+        converter = data['converter'] or 'default'
+        if variable in used_names:
+            raise ValueError('variable name %r used twice.' % variable)
+        used_names.add(variable)
+        yield converter, data['args'] or None, variable
+        pos = m.end()
+    if pos < end:
+        remaining = rule[pos:]
+        if '>' in remaining or '<' in remaining:
+            raise ValueError('malformed url rule: %r' % rule)
+        yield None, None, remaining
+
+
+def get_converter(map, name, args):
+    """Create a new converter for the given arguments or raise
+    exception if the converter does not exist.
+
+    :internal:
+    """
+    if not name in map.converters:
+        raise LookupError('the converter %r does not exist' % name)
+    if args:
+        storage = type('_Storage', (), {'__getitem__': lambda s, x: x})()
+        args, kwargs = eval(u'(lambda *a, **kw: (a, kw))(%s)' % args, {}, storage)
+    else:
+        args = ()
+        kwargs = {}
+    return map.converters[name](map, *args, **kwargs)
+
+
+class RoutingException(Exception):
+    """Special exceptions that require the application to redirect, notifies
+    him about missing urls etc.
+
+    :internal:
+    """
+
+
+class RequestRedirect(HTTPException, RoutingException):
+    """Raise if the map requests a redirect. This is for example the case if
+    `strict_slashes` are activated and an url that requires a leading slash.
+
+    The attribute `new_url` contains the absolute desitination url.
+    """
+    code = 301
+
+    def __init__(self, new_url):
+        RoutingException.__init__(self, new_url)
+        self.new_url = new_url
+
+    def get_response(self, environ):
+        return redirect(self.new_url, 301)
+
+
+class RequestSlash(RoutingException):
+    """Internal exception."""
+
+
+class BuildError(RoutingException, LookupError):
+    """Raised if the build system cannot find a URL for an endpoint with the
+    values provided.
+    """
+
+    def __init__(self, endpoint, values, method):
+        LookupError.__init__(self, endpoint, values, method)
+        self.endpoint = endpoint
+        self.values = values
+        self.method = method
+
+
+class ValidationError(ValueError):
+    """Validation error.  If a rule converter raises this exception the rule
+    does not match the current URL and the next URL is tried.
+    """
+
+
+class RuleFactory(object):
+    """As soon as you have more complex URL setups it's a good idea to use rule
+    factories to avoid repetitive tasks.  Some of them are builtin, others can
+    be added by subclassing `RuleFactory` and overriding `get_rules`.
+    """
+
+    def get_rules(self, map):
+        """Subclasses of `RuleFactory` have to override this method and return
+        an iterable of rules."""
+        raise NotImplementedError()
+
+
+class Subdomain(RuleFactory):
+    """All URLs provided by this factory have the subdomain set to a
+    specific domain. For example if you want to use the subdomain for
+    the current language this can be a good setup::
+
+        url_map = Map([
+            Rule('/', endpoint='#select_language'),
+            Subdomain('<string(length=2):lang_code>', [
+                Rule('/', endpoint='index'),
+                Rule('/about', endpoint='about'),
+                Rule('/help', endpoint='help')
+            ])
+        ])
+
+    All the rules except of the ``'#select_language'`` endpoint will now
+    listen on a two letter long subdomain that helds the language code
+    for the current request.
+    """
+
+    def __init__(self, subdomain, rules):
+        self.subdomain = subdomain
+        self.rules = rules
+
+    def get_rules(self, map):
+        for rulefactory in self.rules:
+            for rule in rulefactory.get_rules(map):
+                rule.subdomain = self.subdomain
+                yield rule
+
+
+class Submount(RuleFactory):
+    """Like `Subdomain` but prefixes the URL rule with a given string::
+
+        url_map = Map([
+            Rule('/', endpoint='index'),
+            Submount('/blog', [
+                Rule('/', endpoint='blog/index'),
+                Rule('/entry/<entry_slug>', endpoint='blog/show')
+            ])
+        ])
+
+    Now the rule ``'blog/show'`` matches ``/blog/entry/<entry_slug>``.
+    """
+
+    def __init__(self, path, rules):
+        self.path = path.rstrip('/')
+        self.rules = rules
+
+    def get_rules(self, map):
+        for rulefactory in self.rules:
+            for rule in rulefactory.get_rules(map):
+                rule.rule = self.path + rule.rule
+                yield rule
+
+
+class EndpointPrefix(RuleFactory):
+    """Prefixes all endpoints (which must be strings for this factory) with
+    another string. This can be useful for sub applications::
+
+        url_map = Map([
+            Rule('/', endpoint='index'),
+            EndpointPrefix('blog/', [Submount('/blog', [
+                Rule('/', endpoint='index'),
+                Rule('/entry/<entry_slug>', endpoint='show')
+            ])])
+        ])
+    """
+
+    def __init__(self, prefix, rules):
+        self.prefix = prefix
+        self.rules = rules
+
+    def get_rules(self, map):
+        for rulefactory in self.rules:
+            for rule in rulefactory.get_rules(map):
+                rule.endpoint = self.prefix + rule.endpoint
+                yield rule
+
+
+class RuleTemplate(object):
+    """Returns copies of the rules wrapped and expands string templates in
+    the endpoint, rule, defaults or subdomain sections.
+
+    Here a small example for such a rule template::
+
+        from werkzeug.routing import Map, Rule, RuleTemplate
+
+        resource = RuleTemplate([
+            Rule('/$name/', endpoint='$name.list'),
+            Rule('/$name/<int:id>', endpoint='$name.show')
+        ])
+
+        url_map = Map([resource(name='user'), resource(name='page')])
+
+    When a rule template is called the keyword arguments are used to
+    replace the placeholders in all the string parameters.
+    """
+
+    def __init__(self, rules):
+        self.rules = list(rules)
+
+    def __call__(self, *args, **kwargs):
+        return RuleTemplateFactory(self.rules, dict(*args, **kwargs))
+
+
+class RuleTemplateFactory(RuleFactory):
+    """A factory that fills in template variables into rules.  Used by
+    `RuleTemplate` internally.
+
+    :internal:
+    """
+
+    def __init__(self, rules, context):
+        self.rules = rules
+        self.context = context
+
+    def get_rules(self, map):
+        for rulefactory in self.rules:
+            for rule in rulefactory.get_rules(map):
+                new_defaults = subdomain = None
+                if rule.defaults is not None:
+                    new_defaults = {}
+                    for key, value in rule.defaults.iteritems():
+                        if isinstance(value, basestring):
+                            value = format_string(value, self.context)
+                        new_defaults[key] = value
+                if rule.subdomain is not None:
+                    subdomain = format_string(rule.subdomain, self.context)
+                new_endpoint = rule.endpoint
+                if isinstance(new_endpoint, basestring):
+                    new_endpoint = format_string(new_endpoint, self.context)
+                yield Rule(
+                    format_string(rule.rule, self.context),
+                    new_defaults,
+                    subdomain,
+                    rule.methods,
+                    rule.build_only,
+                    new_endpoint,
+                    rule.strict_slashes
+                )
+
+
+class Rule(RuleFactory):
+    """A Rule represents one URL pattern.  There are some options for `Rule`
+    that change the way it behaves and are passed to the `Rule` constructor.
+    Note that beside the rule-string all arguments *must* be keyword arguments
+    in order to not break the application on Werkzeug upgrades.
+
+    `string`
+        Rule strings basically are just normal URL paths with placeholders in
+        the format ``<converter(arguments):name>`` where the converter and the
+        arguments are optional.  If no converter is defined the `default`
+        converter is used which means `string` in the normal configuration.
+
+        URL rules that end with a slash are branch URLs, others are leaves.
+        If you have `strict_slashes` enabled (which is the default), all
+        branch URLs that are matched without a trailing slash will trigger a
+        redirect to the same URL with the missing slash appended.
+
+        The converters are defined on the `Map`.
+
+    `endpoint`
+        The endpoint for this rule. This can be anything. A reference to a
+        function, a string, a number etc.  The preferred way is using a string
+        as because the endpoint is used for URL generation.
+
+    `defaults`
+        An optional dict with defaults for other rules with the same endpoint.
+        This is a bit tricky but useful if you want to have unique URLs::
+
+            url_map = Map([
+                Rule('/all/', defaults={'page': 1}, endpoint='all_entries'),
+                Rule('/all/page/<int:page>', endpoint='all_entries')
+            ])
+
+        If a user now visits ``http://example.com/all/page/1`` he will be
+        redirected to ``http://example.com/all/``.  If `redirect_defaults` is
+        disabled on the `Map` instance this will only affect the URL
+        generation.
+
+    `subdomain`
+        The subdomain rule string for this rule. If not specified the rule
+        only matches for the `default_subdomain` of the map.  If the map is
+        not bound to a subdomain this feature is disabled.
+
+        Can be useful if you want to have user profiles on different subdomains
+        and all subdomains are forwarded to your application::
+
+            url_map = Map([
+                Rule('/', subdomain='<username>', endpoint='user/homepage'),
+                Rule('/stats', subdomain='<username>', endpoint='user/stats')
+            ])
+
+    `methods`
+        A sequence of http methods this rule applies to.  If not specified, all
+        methods are allowed. For example this can be useful if you want different
+        endpoints for `POST` and `GET`.  If methods are defined and the path
+        matches but the method matched against is not in this list or in the
+        list of another rule for that path the error raised is of the type
+        `MethodNotAllowed` rather than `NotFound`.
+
+    `strict_slashes`
+        Override the `Map` setting for `strict_slashes` only for this rule. If
+        not specified the `Map` setting is used.
+
+    `build_only`
+        Set this to true and the rule will never match but will create a URL
+        that can be build. This is useful if you have resources on a subdomain
+        or folder that are not handled by the WSGI application (like static data)
+
+    `redirect_to`
+        If given this must be either a string or callable.  In case of a
+        callable it's called with the url adapter that triggered the match and
+        the values of the URL as keyword arguments and has to return the target
+        for the redirect, otherwise it has to be a string with placeholders in
+        rule syntax::
+
+            def foo_with_slug(adapter, id):
+                # ask the database for the slug for the old id.  this of
+                # course has nothing to do with werkzeug.
+                return 'foo/' + Foo.get_slug_for_id(id)
+
+            url_map = Map([
+                Rule('/foo/<slug>', endpoint='foo'),
+                Rule('/some/old/url/<slug>', redirect_to='foo/<slug>'),
+                Rule('/other/old/url/<int:id>', redirect_to=foo_with_slug)
+            ])
+
+        When the rule is matched the routing system will raise a
+        `RequestRedirect` exception with the target for the redirect.
+
+        Keep in mind that the URL will be joined against the URL root of the
+        script so don't use a leading slash on the target URL unless you
+        really mean root of that domain.
+    """
+
+    def __init__(self, string, defaults=None, subdomain=None, methods=None,
+                 build_only=False, endpoint=None, strict_slashes=None,
+                 redirect_to=None):
+        if not string.startswith('/'):
+            raise ValueError('urls must start with a leading slash')
+        self.rule = string
+        self.is_leaf = not string.endswith('/')
+
+        self.map = None
+        self.strict_slashes = strict_slashes
+        self.subdomain = subdomain
+        self.defaults = defaults
+        self.build_only = build_only
+        if methods is None:
+            self.methods = None
+        else:
+            self.methods = set([x.upper() for x in methods])
+        self.endpoint = endpoint
+        self.greediness = 0
+        self.redirect_to = redirect_to
+
+        self._trace = []
+        if defaults is not None:
+            self.arguments = set(map(str, defaults))
+        else:
+            self.arguments = set()
+        self._converters = {}
+        self._regex = None
+        self._weights = []
+
+    def empty(self):
+        """Return an unbound copy of this rule.  This can be useful if you
+        want to reuse an already bound URL for another map."""
+        return Rule(self.rule, self.defaults, self.subdomain, self.methods,
+                    self.build_only, self.endpoint, self.strict_slashes,
+                    self.redirect_to)
+
+    def get_rules(self, map):
+        yield self
+
+    def bind(self, map):
+        """Bind the url to a map and create a regular expression based on
+        the information from the rule itself and the defaults from the map.
+
+        :internal:
+        """
+        if self.map is not None:
+            raise RuntimeError('url rule %r already bound to map %r' %
+                               (self, self.map))
+        self.map = map
+        if self.strict_slashes is None:
+            self.strict_slashes = map.strict_slashes
+        if self.subdomain is None:
+            self.subdomain = map.default_subdomain
+
+        rule = self.subdomain + '|' + (self.is_leaf and self.rule
+                                       or self.rule.rstrip('/'))
+
+        regex_parts = []
+        for converter, arguments, variable in parse_rule(rule):
+            if converter is None:
+                regex_parts.append(re.escape(variable))
+                self._trace.append((False, variable))
+                self._weights.append(len(variable))
+            else:
+                convobj = get_converter(map, converter, arguments)
+                regex_parts.append('(?P<%s>%s)' % (variable, convobj.regex))
+                self._converters[variable] = convobj
+                self._trace.append((True, variable))
+                self._weights.append(convobj.weight)
+                self.arguments.add(str(variable))
+                if convobj.is_greedy:
+                    self.greediness += 1
+        if not self.is_leaf:
+            self._trace.append((False, '/'))
+
+        if not self.build_only:
+            regex = r'^%s%s$' % (
+                u''.join(regex_parts),
+                (not self.is_leaf or not self.strict_slashes) and \
+                    '(?<!/)(?P<__suffix__>/?)' or ''
+            )
+            self._regex = re.compile(regex, re.UNICODE)
+
+    def match(self, path):
+        """Check if the rule matches a given path. Path is a string in the
+        form ``"subdomain|/path(method)"`` and is assembled by the map.
+
+        If the rule matches a dict with the converted values is returned,
+        otherwise the return value is `None`.
+
+        :internal:
+        """
+        if not self.build_only:
+            m = self._regex.search(path)
+            if m is not None:
+                groups = m.groupdict()
+                # we have a folder like part of the url without a trailing
+                # slash and strict slashes enabled. raise an exception that
+                # tells the map to redirect to the same url but with a
+                # trailing slash
+                if self.strict_slashes and not self.is_leaf and \
+                   not groups.pop('__suffix__'):
+                    raise RequestSlash()
+                # if we are not in strict slashes mode we have to remove
+                # a __suffix__
+                elif not self.strict_slashes:
+                    del groups['__suffix__']
+
+                result = {}
+                for name, value in groups.iteritems():
+                    try:
+                        value = self._converters[name].to_python(value)
+                    except ValidationError:
+                        return
+                    result[str(name)] = value
+                if self.defaults is not None:
+                    result.update(self.defaults)
+                return result
+
+    def build(self, values):
+        """Assembles the relative url for that rule and the subdomain.
+        If building doesn't work for some reasons `None` is returned.
+
+        :internal:
+        """
+        tmp = []
+        add = tmp.append
+        processed = set(self.arguments)
+        for is_dynamic, data in self._trace:
+            if is_dynamic:
+                try:
+                    add(self._converters[data].to_url(values[data]))
+                except ValidationError:
+                    return
+                processed.add(data)
+            else:
+                add(data)
+        subdomain, url = (u''.join(tmp)).split('|', 1)
+
+        query_vars = {}
+        for key in set(values) - processed:
+            query_vars[key] = unicode(values[key])
+        if query_vars:
+            url += '?' + url_encode(query_vars, self.map.charset)
+
+        return subdomain, url
+
+    def provides_defaults_for(self, rule):
+        """Check if this rule has defaults for a given rule.
+
+        :internal:
+        """
+        return not self.build_only and self.defaults is not None and \
+               self.endpoint == rule.endpoint and self != rule and \
+               self.arguments == rule.arguments
+
+    def suitable_for(self, values, method):
+        """Check if the dict of values has enough data for url generation.
+
+        :internal:
+        """
+        if self.methods is not None and method not in self.methods:
+            return False
+
+        valueset = set(values)
+
+        for key in self.arguments - set(self.defaults or ()):
+            if key not in values:
+                return False
+
+        if self.arguments.issubset(valueset):
+            if self.defaults is None:
+                return True
+            for key, value in self.defaults.iteritems():
+                if value != values[key]:
+                    return False
+
+        return True
+
+    def match_compare(self, other):
+        """Compare this object with another one for matching.
+
+        :internal:
+        """
+        for sw, ow in izip(self._weights, other._weights):
+            if sw > ow:
+                return -1
+            elif sw < ow:
+                return 1
+        if len(self._weights) > len(other._weights):
+            return -1
+        if len(self._weights) < len(other._weights):
+            return 1
+        if not other.arguments and self.arguments:
+            return 1
+        elif other.arguments and not self.arguments:
+            return -1
+        elif other.defaults is None and self.defaults is not None:
+            return 1
+        elif other.defaults is not None and self.defaults is None:
+            return -1
+        elif self.greediness > other.greediness:
+            return -1
+        elif self.greediness < other.greediness:
+            return 1
+        elif len(self.arguments) > len(other.arguments):
+            return 1
+        elif len(self.arguments) < len(other.arguments):
+            return -1
+        return 1
+
+    def build_compare(self, other):
+        """Compare this object with another one for building.
+
+        :internal:
+        """
+        if not other.arguments and self.arguments:
+            return -1
+        elif other.arguments and not self.arguments:
+            return 1
+        elif other.defaults is None and self.defaults is not None:
+            return -1
+        elif other.defaults is not None and self.defaults is None:
+            return 1
+        elif self.provides_defaults_for(other):
+            return -1
+        elif other.provides_defaults_for(self):
+            return 1
+        elif self.greediness > other.greediness:
+            return -1
+        elif self.greediness < other.greediness:
+            return 1
+        elif len(self.arguments) > len(other.arguments):
+            return -1
+        elif len(self.arguments) < len(other.arguments):
+            return 1
+        return -1
+
+    def __eq__(self, other):
+        return self.__class__ is other.__class__ and \
+               self._trace == other._trace
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def __unicode__(self):
+        return self.rule
+
+    def __str__(self):
+        charset = self.map is not None and self.map.charset or 'utf-8'
+        return unicode(self).encode(charset)
+
+    def __repr__(self):
+        if self.map is None:
+            return '<%s (unbound)>' % self.__class__.__name__
+        charset = self.map is not None and self.map.charset or 'utf-8'
+        tmp = []
+        for is_dynamic, data in self._trace:
+            if is_dynamic:
+                tmp.append('<%s>' % data)
+            else:
+                tmp.append(data)
+        return '<%s %r%s -> %s>' % (
+            self.__class__.__name__,
+            (u''.join(tmp).encode(charset)).lstrip('|'),
+            self.methods is not None and ' (%s)' % \
+                ', '.join(self.methods) or '',
+            self.endpoint
+        )
+
+
+class BaseConverter(object):
+    """Base class for all converters."""
+    regex = '[^/]+'
+    is_greedy = False
+    weight = 100
+
+    def __init__(self, map):
+        self.map = map
+
+    def to_python(self, value):
+        return value
+
+    def to_url(self, value):
+        return url_quote(value, self.map.charset)
+
+
+class UnicodeConverter(BaseConverter):
+    """This converter is the default converter and accepts any string but
+    only one one path segment.  Thus the string can not include a slash.
+
+    Supported arguments:
+
+    - `minlength` - the minimum length of the string. must be greater
+      than 1.
+    - `maxlength` - the maximum length of the string.
+    - `length` - the exact length of that string.
+    """
+
+    def __init__(self, map, minlength=1, maxlength=None, length=None):
+        BaseConverter.__init__(self, map)
+        if length is not None:
+            length = '{%d}' % int(length)
+        else:
+            if maxlength is None:
+                maxlength = ''
+            else:
+                maxlength = int(maxlength)
+            length = '{%s,%s}' % (
+                int(minlength),
+                maxlength
+            )
+        self.regex = '[^/]' + length
+
+
+class AnyConverter(BaseConverter):
+    """Matches one of the items provided.  Items can either be Python
+    identifiers or unicode strings::
+
+        Rule('/<any(about, help, imprint, u"class"):page_name>')
+    """
+
+    def __init__(self, map, *items):
+        BaseConverter.__init__(self, map)
+        self.regex = '(?:%s)' % '|'.join([re.escape(x) for x in items])
+
+
+class PathConverter(BaseConverter):
+    """Like the default string converter, but it also matches slashes."""
+    regex = '[^/].*?'
+    is_greedy = True
+    weight = 50
+
+
+class NumberConverter(BaseConverter):
+    """Baseclass for `IntegerConverter` and `FloatConverter`.
+
+    :internal:
+    """
+
+    def __init__(self, map, fixed_digits=0, min=None, max=None):
+        BaseConverter.__init__(self, map)
+        self.fixed_digits = fixed_digits
+        self.min = min
+        self.max = max
+
+    def to_python(self, value):
+        if (self.fixed_digits and len(value) != self.fixed_digits):
+            raise ValidationError()
+        value = self.num_convert(value)
+        if (self.min is not None and value < self.min) or \
+           (self.max is not None and value > self.max):
+            raise ValidationError()
+        return value
+
+    def to_url(self, value):
+        value = self.num_convert(value)
+        if self.fixed_digits:
+            value = ('%%0%sd' % self.fixed_digits) % value
+        return str(value)
+
+
+class IntegerConverter(NumberConverter):
+    """This converter only accepts integer values::
+
+        Rule('/page/<int:page>')
+
+    Supported arguments:
+
+    - `fixed_digits` - the number of fixed digits in the URL. If you
+      set this to ``4`` for example, the application will only match
+      if the url looks like ``/0001/``.  The default is
+      variable length.
+    - `min` - the minimal value.
+    - `max` - the maximal value.
+    """
+    regex = r'\d+'
+    num_convert = int
+
+
+class FloatConverter(NumberConverter):
+    """This converter only accepts floating point values::
+
+        Rule('/probability/<float:probability>')
+
+    Supported arguments:
+
+    - `min` - the minimal value.
+    - `max` - the maximal value.
+    """
+    regex = r'\d+\.\d+'
+    num_convert = float
+
+    def __init__(self, map, min=None, max=None):
+        NumberConverter.__init__(self, map, 0, min, max)
+
+
+class Map(object):
+    """The map class stores all the URL rules and some configuration
+    parameters.  Some of the configuration values are only stored on the
+    `Map` instance since those affect all rules, others are just defaults
+    and can be overridden for each rule.  Note that you have to specify all
+    arguments beside the `rules` as keywords arguments!
+    """
+
+    def __init__(self, rules=None, default_subdomain='', charset='utf-8',
+                 strict_slashes=True, redirect_defaults=True,
+                 converters=None):
+        """Initializes the new URL map.
+
+        :param rules: sequence of url rules for this map.
+        :param default_subdomain: The default subdomain for rules without a
+                                  subdomain defined.
+        :param charset: charset of the url. defaults to ``"utf-8"``
+        :param strict_slashes: Take care of trailing slashes.
+        :param redirect_defaults: This will redirect to the default rule if it
+                                  wasn't visited that way. This helps creating
+                                  unique URLs.
+        :param converters: A dict of converters that adds additional converters
+                           to the list of converters. If you redefine one
+                           converter this will override the original one.
+        """
+        self._rules = []
+        self._rules_by_endpoint = {}
+        self._remap = True
+
+        self.default_subdomain = default_subdomain
+        self.charset = charset
+        self.strict_slashes = strict_slashes
+        self.redirect_defaults = redirect_defaults
+
+        self.converters = DEFAULT_CONVERTERS.copy()
+        if converters:
+            self.converters.update(converters)
+
+        for rulefactory in rules or ():
+            self.add(rulefactory)
+
+    def is_endpoint_expecting(self, endpoint, *arguments):
+        """Iterate over all rules and check if the endpoint expects
+        the arguments provided.  This is for example useful if you have
+        some URLs that expect a language code and others that do not and
+        you want to wrap the builder a bit so that the current language
+        code is automatically added if not provided but endpoints expect
+        it.
+        """
+        self.update()
+        arguments = set(arguments)
+        for rule in self._rules_by_endpoint[endpoint]:
+            if arguments.issubset(rule.arguments):
+                return True
+        return False
+
+    def iter_rules(self, endpoint=None):
+        """Iterate over all rules or the rules of an endpoint."""
+        if endpoint is not None:
+            return iter(self._rules_by_endpoint[endpoint])
+        return iter(self._rules)
+
+    def add(self, rulefactory):
+        """Add a new rule or factory to the map and bind it.  Requires that the
+        rule is not bound to another map.
+        """
+        for rule in rulefactory.get_rules(self):
+            rule.bind(self)
+            self._rules.append(rule)
+            self._rules_by_endpoint.setdefault(rule.endpoint, []).append(rule)
+        self._remap = True
+
+    def add_rule(self, rule):
+        from warnings import warn
+        warn(DeprecationWarning('use map.add instead of map.add_rule now'))
+        return self.add(rule)
+
+    def bind(self, server_name, script_name=None, subdomain=None,
+             url_scheme='http', default_method='GET', path_info=None):
+        """Return a new `MapAdapter` with the details specified to the call.
+        Note that `script_name` will default to ``'/'`` if not further
+        specified or `None`.  The `server_name` at least is a requirement
+        because the HTTP RFC requires absolute URLs for redirects and so all
+        redirect exceptions raised by Werkzeug will contain the full canonical
+        URL.
+
+        If no path_info is passed to match() it will use the default path
+        info passed to bind.  While this doesn't really make sense for
+        manual bind calls, it's useful if you bind a map to a WSGI
+        environment which already contains the path info.
+
+        `subdomain` will default to the `default_subdomain` for this map if
+        no defined. If there is no `default_subdomain` you cannot use the
+        subdomain feature.
+        """
+        if subdomain is None:
+            subdomain = self.default_subdomain
+        if script_name is None:
+            script_name = '/'
+        return MapAdapter(self, server_name, script_name, subdomain,
+                          url_scheme, path_info, default_method)
+
+    def bind_to_environ(self, environ, server_name=None, subdomain=None,
+                        calculate_subdomain=False):
+        """Like `bind` but you can pass it an WSGI environment and it will
+        fetch the information from that directory.  Note that because of
+        limitations in the protocol there is no way to get the current
+        subdomain and real `server_name` from the environment.  If you don't
+        provide it, Werkzeug will use `SERVER_NAME` and `SERVER_PORT` (or
+        `HTTP_HOST` if provided) as used `server_name` with disabled subdomain
+        feature.
+
+        If `subdomain` is `None` but an environment and a server name is
+        provided it will calculate the current subdomain automatically.
+        Example: `server_name` is ``'example.com'`` and the `SERVER_NAME`
+        in the wsgi `environ` is ``'staging.dev.example.com'`` the calculated
+        subdomain will be ``'staging.dev'``.
+
+        If the object passed as environ as an environ attribute, the value of
+        this attribute is used instead.  This allows you to pass request
+        objects.  Additionally `PATH_INFO` added as a default ot the
+        `MapAdapter` so that you don't have to pass the path info to the
+        match method.
+        """
+        if hasattr(environ, 'environ'):
+            environ = environ.environ
+        if server_name is None:
+            if 'HTTP_HOST' in environ:
+                server_name = environ['HTTP_HOST']
+            else:
+                server_name = environ['SERVER_NAME']
+                if (environ['wsgi.url_scheme'], environ['SERVER_PORT']) not \
+                   in (('https', '443'), ('http', '80')):
+                    server_name += ':' + environ['SERVER_PORT']
+        elif subdomain is None:
+            cur_server_name = environ['SERVER_NAME'].split('.')
+            real_server_name = server_name.split(':', 1)[0].split('.')
+            offset = -len(real_server_name)
+            if cur_server_name[offset:] != real_server_name:
+                raise ValueError('the server name provided (%r) does not '
+                                 'match the server name from the WSGI '
+                                 'environment (%r)' %
+                                 (environ['SERVER_NAME'], server_name))
+            subdomain = '.'.join(filter(None, cur_server_name[:offset]))
+        return Map.bind(self, server_name, environ.get('SCRIPT_NAME'),
+                        subdomain, environ['wsgi.url_scheme'],
+                        environ['REQUEST_METHOD'], environ.get('PATH_INFO'))
+
+    def update(self):
+        """Called before matching and building to keep the compiled rules
+        in the correct order after things changed.
+        """
+        if self._remap:
+            self._rules.sort(lambda a, b: a.match_compare(b))
+            for rules in self._rules_by_endpoint.itervalues():
+                rules.sort(lambda a, b: a.build_compare(b))
+            self._remap = False
+
+
+class MapAdapter(object):
+    """Retured by `Map.bind` or `Map.bind_to_environ` and does the
+    URL matching and building based on runtime information.
+    """
+
+    def __init__(self, map, server_name, script_name, subdomain,
+                 url_scheme, path_info, default_method):
+        self.map = map
+        self.server_name = server_name
+        if not script_name.endswith('/'):
+            script_name += '/'
+        self.script_name = script_name
+        self.subdomain = subdomain
+        self.url_scheme = url_scheme
+        self.path_info = path_info or u''
+        self.default_method = default_method
+
+    def dispatch(self, view_func, path_info=None, method=None,
+                 catch_http_exceptions=False):
+        """Does the complete dispatching process.  `view_func` is called with
+        the endpoint and a dict with the values for the view.  It should
+        look up the view function, call it, and return a response object
+        or WSGI application.  http exceptions are not catched by default
+        so that applications can display nicer error messages by just
+        catching them by hand.  If you want to stick with the default
+        error messages you can pass it ``catch_http_exceptions=True`` and
+        it will catch the http exceptions.
+
+        Here a small example for the dispatch usage::
+
+            from werkzeug import Request, Response, responder
+            from werkzeug.routing import Map, Rule
+
+            def on_index(request):
+                return Response('Hello from the index')
+
+            url_map = Map([Rule('/', endpoint='index')])
+            views = {'index': on_index}
+
+            @responder
+            def application(environ, start_response):
+                request = Request(environ)
+                urls = url_map.bind_to_environ(environ)
+                return urls.dispatch(lambda e, v: views[e](request, **v),
+                                     catch_http_exceptions=True)
+
+        Keep in mind that this method might return exception objects too, so
+        use `Response.force_type` to get a response object.
+        """
+        try:
+            try:
+                endpoint, args = self.match(path_info, method)
+            except RequestRedirect, e:
+                return e
+            return view_func(endpoint, args)
+        except HTTPException, e:
+            if catch_http_exceptions:
+                return e
+            raise
+
+    def match(self, path_info=None, method=None):
+        """The usage is simple: you just pass the match method the current
+        path info as well as the method (which defaults to `GET`).  The
+        following things can then happen:
+
+        - you receive a `NotFound` exception that indicates that no URL is
+          matching.  A `NotFound` exception is also a WSGI application you
+          can call to get a default page not found page (happens to be the
+          same object as `werkzeug.exceptions.NotFound`)
+
+        - you receive a `MethodNotAllowed` exception that indicates that there
+          is a match for this URL but non for the current request method.
+          This is useful for RESTful applications.
+
+        - you receive a `RequestRedirect` exception with a `new_url`
+          attribute.  This exception is used to notify you about a request
+          Werkzeug requests by your WSGI application.  This is for example the
+          case if you request ``/foo`` although the correct URL is ``/foo/``
+          You can use the `RequestRedirect` instance as response-like object
+          similar to all other subclasses of `HTTPException`.
+
+        - you get a tuple in the form ``(endpoint, arguments)`` when there is
+          a match.
+
+        If the path info is not passed to the match method the default path
+        info of the map is used (defaults to the root URL if not defined
+        explicitly).
+
+        All of the exceptions raised are subclasses of `HTTPException` so they
+        can be used as WSGI responses.  The will all render generic error or
+        redirect pages.
+
+        Here is a small example for matching:
+
+        >>> from werkzeug.routing import Map, Rule
+        >>> m = Map([
+        ...     Rule('/', endpoint='index'),
+        ...     Rule('/downloads/', endpoint='downloads/index'), 
+        ...     Rule('/downloads/<int:id>', endpoint='downloads/show')
+        ... ])
+        >>> urls = m.bind("example.com", "/")
+        >>> urls.match("/", "GET")
+        ('index', {})
+        >>> urls.match("/downloads/42")
+        ('downloads/show', {'id': 42})
+
+        And here is what happens on redirect and missing URLs:
+
+        >>> urls.match("/downloads")
+        Traceback (most recent call last):
+          ...
+        werkzeug.routing.RequestRedirect: http://example.com/downloads/
+        >>> urls.match("/missing")
+        Traceback (most recent call last):
+          ...
+        werkzeug.routing.NotFound: /missing
+        """
+        self.map.update()
+        if path_info is None:
+            path_info = self.path_info
+        if not isinstance(path_info, unicode):
+            path_info = path_info.decode(self.map.charset, 'ignore')
+        method = (method or self.default_method).upper()
+        path = u'%s|/%s' % (self.subdomain, path_info.lstrip('/'))
+        have_match_for = set()
+        for rule in self.map._rules:
+            try:
+                rv = rule.match(path)
+            except RequestSlash:
+                raise RequestRedirect(str('%s://%s%s%s/%s/' % (
+                    self.url_scheme,
+                    self.subdomain and self.subdomain + '.' or '',
+                    self.server_name,
+                    self.script_name[:-1],
+                    path_info.lstrip('/')
+                )))
+            if rv is None:
+                continue
+            if rule.methods is not None and method not in rule.methods:
+                have_match_for.update(rule.methods)
+                continue
+            if self.map.redirect_defaults:
+                for r in self.map._rules_by_endpoint[rule.endpoint]:
+                    if r.provides_defaults_for(rule) and \
+                       r.suitable_for(rv, method):
+                        rv.update(r.defaults)
+                        subdomain, path = r.build(rv)
+                        raise RequestRedirect(str('%s://%s%s%s/%s' % (
+                            self.url_scheme,
+                            subdomain and subdomain + '.' or '',
+                            self.server_name,
+                            self.script_name[:-1],
+                            path.lstrip('/')
+                        )))
+            if rule.redirect_to is not None:
+                if isinstance(rule.redirect_to, basestring):
+                    def _handle_match(match):
+                        value = rv[match.group(1)]
+                        return rule._converters[match.group(1)].to_url(value)
+                    redirect_url = _simple_rule_re.sub(_handle_match,
+                                                       rule.redirect_to)
+                else:
+                    redirect_url = rule.redirect_to(self, **rv)
+                raise RequestRedirect(str(urljoin('%s://%s%s%s' % (
+                    self.url_scheme,
+                    self.subdomain and self.subdomain + '.' or '',
+                    self.server_name,
+                    self.script_name
+                ), redirect_url)))
+            return rule.endpoint, rv
+        if have_match_for:
+            raise MethodNotAllowed(valid_methods=list(have_match_for))
+        raise NotFound()
+
+    def test(self, path_info=None, method=None):
+        """Test if a rule would match.  Works like `match` but returns `True`
+        if the URL matches, or `False` if it does not exist.
+        """
+        try:
+            self.match(path_info, method)
+        except RequestRedirect:
+            pass
+        except NotFound:
+            return False
+        return True
+
+    def build(self, endpoint, values=None, method=None, force_external=False):
+        """Building URLs works pretty much the other way round.  Instead of
+        `match` you call `build` and pass it the endpoint and a dict of
+        arguments for the placeholders.
+
+        The `build` function also accepts an argument called `force_external`
+        which, if you set it to `True` will force external URLs. Per default
+        external URLs (include the server name) will only be used if the
+        target URL is on a
+        different subdomain.
+
+        With the same map as in the example above this code generates some
+        target URLs:
+
+        >>> urls.build("index", {})
+        '/'
+        >>> urls.build("downloads/show", {'id': 42})
+        '/downloads/42'
+        >>> urls.build("downloads/show", {'id': 42}, force_external=True)
+        'http://example.com/downloads/42'
+
+        Because URLs cannot contain non ASCII data you will always get
+        bytestrings back.  Non ASCII characters are urlencoded with the
+        charset defined on the map instance.
+
+        Additional values are converted to unicode and appended to the URL as
+        URL querystring parameters:
+
+        >>> urls.build("index", {'q': 'My Searchstring'})
+        '/?q=My+Searchstring'
+
+        If a rule does not exist when building a `BuildError` exception is
+        raised.
+
+        The build method accepts an argument called `method` which allows you
+        to specify the method you want to have an URL builded for if you have
+        different methods for the same endpoint specified.
+        """
+        self.map.update()
+        method = method or self.default_method
+        if values:
+            values = dict([(k, v) for k, v in values.items() if v is not None])
+        else:
+            values = {}
+
+        for rule in self.map._rules_by_endpoint.get(endpoint, ()):
+            if rule.suitable_for(values, method):
+                rv = rule.build(values)
+                if rv is not None:
+                    break
+        else:
+            raise BuildError(endpoint, values, method)
+        subdomain, path = rv
+        if not force_external and subdomain == self.subdomain:
+            return str(urljoin(self.script_name, path.lstrip('/')))
+        return str('%s://%s%s%s/%s' % (
+            self.url_scheme,
+            subdomain and subdomain + '.' or '',
+            self.server_name,
+            self.script_name[:-1],
+            path.lstrip('/')
+        ))
+
+
+#: the default converter mapping for the map.
+DEFAULT_CONVERTERS = {
+    'default':          UnicodeConverter,
+    'string':           UnicodeConverter,
+    'any':              AnyConverter,
+    'path':             PathConverter,
+    'int':              IntegerConverter,
+    'float':            FloatConverter
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/script.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,269 @@
+# -*- coding: utf-8 -*-
+r'''
+    werkzeug.script
+    ~~~~~~~~~~~~~~~
+
+    Most of the time you have recurring tasks while writing an application
+    such as starting up an interactive python interpreter with some prefilled
+    imports, starting the development server, initializing the database or
+    something similar.
+
+    For that purpose werkzeug provides the `werkzeug.script` module which
+    helps you writing such scripts.
+
+
+    Basic Usage
+    -----------
+
+    The following snippet is roughly the same in every werkzeug script::
+
+        #!/usr/bin/env python
+        # -*- coding: utf-8 -*-
+        from werkzeug import script
+
+        # actions go here
+
+        if __name__ == '__main__':
+            script.run()
+
+    Starting this script now does nothing because no actions are defined.
+    An action is a function in the same module starting with ``"action_"``
+    which takes a number of arguments where every argument has a default.  The
+    type of the default value specifies the type of the argument.
+
+    Arguments can then be passed by position or using ``--name=value`` from
+    the shell.
+
+    Because a runserver and shell command is pretty common there are two
+    factory functions that create such commands::
+
+        def make_app():
+            from yourapplication import YourApplication
+            return YourApplication(...)
+
+        action_runserver = script.make_runserver(make_app, use_reloader=True)
+        action_shell = script.make_shell(lambda: {'app': make_app()})
+
+
+    Using The Scripts
+    -----------------
+
+    The script from above can be used like this from the shell now:
+
+    .. sourcecode:: text
+
+        $ ./manage.py --help
+        $ ./manage.py runserver localhost 8080 --debugger --no-reloader
+        $ ./manage.py runserver -p 4000
+        $ ./manage.py shell
+
+    As you can see it's possible to pass parameters as positional arguments
+    or as named parameters, pretty much like Python function calls.
+
+
+    :copyright: 2007-2008 by Armin Ronacher, Thomas Johansson.
+    :license: BSD, see LICENSE for more details.
+'''
+import sys
+import inspect
+import getopt
+from os.path import basename
+try:
+    set = set
+except NameError:
+    from sets import Set as set
+
+
+argument_types = {
+    bool:       'boolean',
+    str:        'string',
+    int:        'integer',
+    float:      'float'
+}
+
+
+converters = {
+    'boolean':  lambda x: x.lower() in ('1', 'true', 'yes', 'on'),
+    'string':   str,
+    'integer':  int,
+    'float':    float
+}
+
+
+def run(namespace=None, action_prefix='action_', args=None):
+    """Run the script.  Participating actions are looked up in the callers
+    namespace if no namespace is given, otherwise in the dict provided.
+    Only items that start with action_prefix are processed as actions.  If
+    you want to use all items in the namespace provided as actions set
+    action_prefix to an empty string."""
+    if namespace is None:
+        namespace = sys._getframe(1).f_locals
+    actions = find_actions(namespace, action_prefix)
+
+    if args is None:
+        args = sys.argv[1:]
+    if not args or args[0] in ('-h', '--help'):
+        return print_usage(actions)
+    elif args[0] not in actions:
+        fail('Unknown action \'%s\'' % args[0])
+
+    arguments = {}
+    conv = {}
+    key_to_arg = {}
+    long_options = []
+    formatstring = ''
+    func, doc, arg_def = actions[args.pop(0)]
+    for idx, (arg, shortcut, default, option_type) in enumerate(arg_def):
+        real_arg = arg.replace('-', '_')
+        converter = converters[option_type]
+        if shortcut:
+            formatstring += shortcut
+            if not isinstance(default, bool):
+                formatstring += ':'
+            key_to_arg['-' + shortcut] = real_arg
+        long_options.append(isinstance(default, bool) and arg or arg + '=')
+        key_to_arg['--' + arg] = real_arg
+        key_to_arg[idx] = real_arg
+        conv[real_arg] = converter
+        arguments[real_arg] = default
+
+    try:
+        optlist, posargs = getopt.gnu_getopt(args, formatstring, long_options)
+    except getopt.GetoptError, e:
+        fail(str(e))
+
+    specified_arguments = set()
+    for key, value in enumerate(posargs):
+        try:
+            arg = key_to_arg[key]
+        except IndexError:
+            fail('Too many parameters')
+        specified_arguments.add(arg)
+        try:
+            arguments[arg] = conv[arg](value)
+        except ValueError:
+            fail('Invalid value for argument %s (%s): %s' % (key, arg, value))
+
+    for key, value in optlist:
+        arg = key_to_arg[key]
+        if arg in specified_arguments:
+            fail('Argument \'%s\' is specified twice' % arg)
+        if arg.startswith('no_'):
+            value = 'no'
+        elif not value:
+            value = 'yes'
+        try:
+            arguments[arg] = conv[arg](value)
+        except ValueError:
+            fail('Invalid value for \'%s\': %s' % (key, value))
+
+    newargs = {}
+    for k, v in arguments.iteritems():
+        newargs[k.startswith('no_') and k[3:] or k] = v
+    arguments = newargs
+    return func(**arguments)
+
+
+def fail(message, code=-1):
+    """Fail with an error."""
+    print >> sys.stderr, 'Error:', message
+    sys.exit(code)
+
+
+def find_actions(namespace, action_prefix):
+    """Find all the actions in the namespace."""
+    actions = {}
+    for key, value in namespace.iteritems():
+        if key.startswith(action_prefix):
+            actions[key[len(action_prefix):]] = analyse_action(value)
+    return actions
+
+
+def print_usage(actions):
+    """Print the usage information.  (Help screen)"""
+    actions = actions.items()
+    actions.sort()
+    print 'usage: %s <action> [<options>]' % basename(sys.argv[0])
+    print '       %s --help' % basename(sys.argv[0])
+    print
+    print 'actions:'
+    for name, (func, doc, arguments) in actions:
+        print '  %s:' % name
+        for line in doc.splitlines():
+            print '    %s' % line
+        if arguments:
+            print
+        for arg, shortcut, default, argtype in arguments:
+            if isinstance(default, bool):
+                print '    %s' % (
+                    (shortcut and '-%s, ' % shortcut or '') + '--' + arg
+                )
+            else:
+                print '    %-30s%-10s%s' % (
+                    (shortcut and '-%s, ' % shortcut or '') + '--' + arg,
+                    argtype, default
+                )
+        print
+
+
+def analyse_action(func):
+    """Analyse a function."""
+    description = inspect.getdoc(func) or 'undocumented action'
+    arguments = []
+    args, varargs, kwargs, defaults = inspect.getargspec(func)
+    if varargs or kwargs:
+        raise TypeError('variable length arguments for action not allowed.')
+    if len(args) != len(defaults or ()):
+        raise TypeError('not all arguments have proper definitions')
+
+    for idx, (arg, definition) in enumerate(zip(args, defaults or ())):
+        if arg.startswith('_'):
+            raise TypeError('arguments may not start with an underscore')
+        if not isinstance(definition, tuple):
+            shortcut = None
+            default = definition
+        else:
+            shortcut, default = definition
+        argument_type = argument_types[type(default)]
+        if isinstance(default, bool) and default is True:
+            arg = 'no-' + arg
+        arguments.append((arg.replace('_', '-'), shortcut,
+                          default, argument_type))
+    return func, description, arguments
+
+
+def make_shell(init_func=lambda: {}, banner=None, use_ipython=True):
+    """Returns an action callback that spawns a new interactive
+    python shell."""
+    if banner is None:
+        banner = 'Interactive Werkzeug Shell'
+    def action(ipython=use_ipython):
+        """Start a new interactive python session."""
+        namespace = init_func()
+        if ipython:
+            try:
+                import IPython
+            except ImportError:
+                pass
+            else:
+                sh = IPython.Shell.IPShellEmbed(banner=banner)
+                sh(global_ns={}, local_ns=namespace)
+                return
+        from code import interact
+        interact(banner, local=namespace)
+    return action
+
+
+def make_runserver(app_factory, hostname='localhost', port=5000,
+                   use_reloader=False, use_debugger=False, use_evalex=True,
+                   threaded=False, processes=1):
+    """Returns an action callback that spawns a new wsgiref server."""
+    def action(hostname=('h', hostname), port=('p', port),
+               reloader=use_reloader, debugger=use_debugger,
+               evalex=use_evalex, threaded=threaded, processes=processes):
+        """Start a new development server."""
+        from werkzeug.serving import run_simple
+        app = app_factory()
+        run_simple(hostname, port, app, reloader, debugger, evalex,
+                   None, 1, threaded, processes)
+    return action
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/serving.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,254 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.serving
+    ~~~~~~~~~~~~~~~~
+
+    There are many ways to serve a WSGI application.  While you're developing
+    it you usually don't want a full blown webserver like Apache but a simple
+    standalone one.  With Python 2.5 onwards there is the `wsgiref`_ server in
+    the standard library.  If you're using older versions of Python you can
+    download the package from the cheeseshop.
+
+    However there are some caveats. Sourcecode won't reload itself when
+    changed and each time you kill the server using ``^C`` you get an
+    `KeyboardInterrupt` error.  While the latter is easy to solve the first
+    one can be a pain in the ass in some situations.
+
+    Because of that Werkzeug ships a small wrapper over `wsgiref` that spawns
+    the WSGI application in a subprocess and automatically reloads the
+    application if a module was changed.
+
+    The easiest way is creating a small ``start-myproject.py`` that runs the
+    application::
+
+        #!/usr/bin/env python
+        # -*- coding: utf-8 -*-
+        from myproject import make_app
+        from werkzeug import run_simple
+
+        app = make_app(...)
+        run_simple('localhost', 8080, app, use_reloader=True)
+
+    You can also pass it a `extra_files` keyword argument with a list of
+    additional files (like configuration files) you want to observe.
+
+    For bigger applications you should consider using `werkzeug.script`
+    instead of a simple start file.
+
+    .. _wsgiref: http://cheeseshop.python.org/pypi/wsgiref
+
+
+    :copyright: 2007-2008 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+import os
+import socket
+import sys
+import time
+import thread
+from itertools import chain
+try:
+    from wsgiref.simple_server import ServerHandler, WSGIRequestHandler, \
+         WSGIServer
+    have_wsgiref = True
+except ImportError:
+    have_wsgiref = False
+from SocketServer import ThreadingMixIn, ForkingMixIn
+from werkzeug._internal import _log
+
+
+if have_wsgiref:
+    class BaseRequestHandler(WSGIRequestHandler):
+        """
+        Subclass of the normal request handler that thinks it is
+        threaded or something like that. The default wsgiref handler
+        has wrong information so we need this class.
+        """
+        multithreaded = False
+        multiprocess = False
+        _handler_class = None
+
+        def get_handler(self):
+            handler = self._handler_class
+            if handler is None:
+                class handler(ServerHandler):
+                    wsgi_multithread = self.multithreaded
+                    wsgi_multiprocess = self.multiprocess
+                self._handler_class = handler
+
+            rv = handler(self.rfile, self.wfile, self.get_stderr(),
+                         self.get_environ())
+            rv.request_handler = self
+            return rv
+
+        def handle(self):
+            self.raw_requestline = self.rfile.readline()
+            if self.parse_request():
+                self.get_handler().run(self.server.get_app())
+
+        def log_request(self, code='-', size='-'):
+            _log('info', '%s -- [%s] %s %s',
+                self.address_string(),
+                self.requestline,
+                code,
+                size
+            )
+
+        def log_error(self, format, *args):
+            _log('error', 'Error: %s', format % args)
+
+        def log_message(self, format, *args):
+            _log('info', format, args)
+
+
+def make_server(host, port, app=None, threaded=False, processes=1,
+                request_handler=None):
+    """Create a new wsgiref server that is either threaded, or forks
+    or just processes one request after another.
+    """
+    if not have_wsgiref:
+        raise RuntimeError('All the Werkzeug serving features require '
+                           'an installed wsgiref library.')
+    request_handler = request_handler or BaseRequestHandler
+    if threaded and processes > 1:
+        raise ValueError("cannot have a multithreaded and "
+                         "multi process server.")
+    elif threaded:
+        class request_handler(request_handler):
+            multithreaded = True
+        class server(ThreadingMixIn, WSGIServer):
+            pass
+    elif processes > 1:
+        class request_handler(request_handler):
+            multiprocess = True
+        class server(ForkingMixIn, WSGIServer):
+            max_children = processes - 1
+    else:
+        server = WSGIServer
+    srv = server((host, port), request_handler)
+    srv.set_app(app)
+    return srv
+
+
+def reloader_loop(extra_files=None, interval=1):
+    """When this function is run from the main thread, it will force other
+    threads to exit when any modules currently loaded change.
+
+    Copyright notice.  This function is based on the autoreload.py from
+    the CherryPy trac which originated from WSGIKit which is now dead.
+
+    :param extra_files: a list of additional files it should watch.
+    """
+    def iter_module_files():
+        for module in sys.modules.values():
+            filename = getattr(module, '__file__', None)
+            if filename:
+                while not os.path.isfile(filename):
+                    filename = os.path.dirname(filename)
+                    if not filename:
+                        break
+                else:
+                    if filename[-4:] in ('.pyc', '.pyo'):
+                        filename = filename[:-1]
+                    yield filename
+
+    mtimes = {}
+    while 1:
+        for filename in chain(iter_module_files(), extra_files or ()):
+            try:
+                mtime = os.stat(filename).st_mtime
+            except OSError:
+                continue
+
+            old_time = mtimes.get(filename)
+            if old_time is None:
+                mtimes[filename] = mtime
+                continue
+            elif mtime > old_time:
+                _log('info', ' * Detected change in %r, reloading' % filename)
+                sys.exit(3)
+        time.sleep(interval)
+
+
+def restart_with_reloader():
+    """Spawn a new Python interpreter with the same arguments as this one,
+    but running the reloader thread.
+    """
+    while 1:
+        _log('info', ' * Restarting with reloader...')
+        args = [sys.executable] + sys.argv
+        if sys.platform == 'win32':
+            args = ['"%s"' % arg for arg in args]
+        new_environ = os.environ.copy()
+        new_environ['WERKZEUG_RUN_MAIN'] = 'true'
+        exit_code = os.spawnve(os.P_WAIT, sys.executable, args, new_environ)
+        if exit_code != 3:
+            return exit_code
+
+
+def run_with_reloader(main_func, extra_files=None, interval=1):
+    """Run the given function in an independent python interpreter."""
+    if os.environ.get('WERKZEUG_RUN_MAIN') == 'true':
+        thread.start_new_thread(main_func, ())
+        try:
+            reloader_loop(extra_files, interval)
+        except KeyboardInterrupt:
+            return
+    try:
+        sys.exit(restart_with_reloader())
+    except KeyboardInterrupt:
+        pass
+
+
+def run_simple(hostname, port, application, use_reloader=False,
+               use_debugger=False, use_evalex=True,
+               extra_files=None, reloader_interval=1, threaded=False,
+               processes=1, request_handler=None):
+    """Start an application using wsgiref and with an optional reloader.  This
+    wraps `wsgiref` to fix the wrong default reporting of the multithreaded
+    WSGI variable and adds optional multithreading and fork support.
+
+    :param hostname: The host for the application.  eg: ``'localhost'``
+    :param port: The port for the server.  eg: ``8080``
+    :param application: the WSGI application to execute
+    :param use_reloader: should the server automatically restart the python
+                         process if modules were changed?
+    :param use_debugger: should the werkzeug debugging system be used?
+    :param use_evalex: should the exception evaluation feature be enabled?
+    :param extra_files: a list of files the reloader should listen for
+                        additionally to the modules.  For example configuration
+                        files.
+    :param reloader_interval: the interval for the reloader in seconds.
+    :param threaded: should the process handle each request in a separate
+                     thread?
+    :param processes: number of processes to spawn.
+    :param request_handler: optional parameter that can be used to replace
+                            the default wsgiref request handler.  Have a look
+                            at the `werkzeug.serving` sourcecode for more
+                            details.
+    """
+    if use_debugger:
+        from werkzeug.debug import DebuggedApplication
+        application = DebuggedApplication(application, use_evalex)
+
+    def inner():
+        srv = make_server(hostname, port, application, threaded,
+                          processes, request_handler)
+        try:
+            srv.serve_forever()
+        except KeyboardInterrupt:
+            pass
+
+    if os.environ.get('WERKZEUG_RUN_MAIN') != 'true':
+        display_hostname = hostname or '127.0.0.1'
+        _log('info', ' * Running on http://%s:%d/', display_hostname, port)
+    if use_reloader:
+        # Create and destroy a socket so that any exceptions are raised before
+        # we spawn a separate Python interpreter and loose this ability.
+        test_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        test_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        test_socket.bind((hostname, port))
+        test_socket.close()
+        run_with_reloader(inner, extra_files, reloader_interval)
+    else:
+        inner()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/templates.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,510 @@
+# -*- coding: utf-8 -*-
+r"""
+    werkzeug.templates
+    ~~~~~~~~~~~~~~~~~~
+
+    This template engine recognizes ASP/PHP like blocks and executes the code
+    in them::
+
+        t = Template('<% for u in users %>${u["username"]}\n<% endfor %>')
+        t.render(users=[{'username': 'John'},
+                        {'username': 'Jane'}])
+
+    would result in::
+
+        John
+        Jane
+
+    You can also create templates from files::
+
+        t = Template.from_file('test.html')
+
+    The syntax elements are a mixture of django, genshi text and mod_python
+    templates and used internally in werkzeug components.
+
+    We do not recommend using this template engine in a real environment
+    because is quite slow and does not provide any advanced features.  For
+    simple applications (cgi script like) this can however be sufficient.
+
+
+    Syntax Elements
+    ---------------
+
+    Printing Variables:
+
+    .. sourcecode:: text
+
+        $variable
+        $variable.attribute[item](some, function)(calls)
+        ${expression} or <%py print expression %>
+
+    Keep in mind that the print statement adds a newline after the call or
+    a whitespace if it ends with a comma.
+
+    For Loops:
+
+    .. sourcecode:: text
+
+        <% for item in seq %>
+            ...
+        <% endfor %>
+
+    While Loops:
+
+    .. sourcecode:: text
+
+        <% while expression %>
+            <%py break / continue %>
+        <% endwhile %>
+
+    If Conditions:
+
+    .. sourcecode:: text
+
+        <% if expression %>
+            ...
+        <% elif expression %>
+            ...
+        <% else %>
+            ...
+        <% endif %>
+
+    Python Expressions:
+
+    .. sourcecode:: text
+
+        <%py
+            ...
+        %>
+
+        <%python
+            ...
+        %>
+
+    Note on python expressions:  You cannot start a loop in a python block
+    and continue it in another one.  This example does *not* work:
+
+    .. sourcecode:: text
+
+        <%python
+            for item in seq:
+        %>
+            ...
+
+    Comments:
+
+    .. sourcecode:: text
+
+        <%#
+            This is a comment
+        %>
+
+
+    Missing Variables
+    -----------------
+
+    If you try to access a missing variable you will get back an `Undefined`
+    object.  You can iterate over such an object or print it and it won't
+    fail.  However every other operation will raise an error.  To test if a
+    variable is undefined you can use this expression:
+
+    .. sourcecode:: text
+
+        <% if variable is Undefined %>
+            ...
+        <% endif %>
+
+
+    Python 2.3 Compatibility
+    ------------------------
+
+    Because of limitations in Python 2.3 it's impossible to achieve the
+    semi-silent variable lookup fallback.  If a template relies on undefined
+    variables it won't execute under Python 2.3.
+
+
+    :copyright: 2006-2008 by Armin Ronacher, Ka-Ping Yee.
+    :license: BSD License.
+"""
+import sys
+import re
+import __builtin__ as builtins
+from compiler import ast, parse
+from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL
+from compiler.pycodegen import ModuleCodeGenerator
+from tokenize import PseudoToken
+from werkzeug import utils
+from werkzeug._internal import _decode_unicode
+
+# Anything older than Python 2.4 
+if sys.version_info < (2, 4):
+    class AstMangler(object):
+
+        def __getattr__(self, key):
+            class_ = getattr(_ast, key)
+            def wrapper(*args, **kw):
+                lineno = kw.pop('lineno', None)
+                obj = class_(*args, **kw)
+                obj.lineno = lineno
+                return obj
+            return wrapper
+
+    _ast = ast
+    ast = AstMangler()
+
+
+# Copyright notice: The `parse_data` method uses the string interpolation
+# algorithm by Ka-Ping Yee which originally was part of `ltpl20.py`_
+#
+# .. _ltipl20.py: http://lfw.org/python/Itpl20.py
+
+
+token_re = re.compile('%s|%s(?s)' % (
+    r'[uU]?[rR]?("""|\'\'\')((?<!\\)\\\1|.)*?\1',
+    PseudoToken
+))
+directive_re = re.compile(r'(?<!\\)<%(?:(#)|(py(?:thon)?\b)|'
+                          r'(?:\s*(\w+))\s*)(.*?)\s*%>\n?(?s)')
+escape_re = re.compile(r'\\\n|\\(\\|<%)')
+namestart_chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_'
+undefined = type('UndefinedType', (object,), {
+    '__iter__': lambda x: iter(()),
+    '__repr__': lambda x: 'Undefined',
+    '__str__':  lambda x: ''
+})()
+runtime_vars = dict.fromkeys(('Undefined', '__to_unicode', '__context',
+                              '__write', '__write_many'))
+
+
+def call_stmt(func, args, lineno):
+    return ast.CallFunc(ast.Name(func, lineno=lineno),
+                        args, lineno=lineno)
+
+
+def tokenize(source, filename):
+    escape = escape_re.sub
+    escape_repl = lambda m: m.group(1) or ''
+    lineno = 1
+    pos = 0
+
+    for match in directive_re.finditer(source):
+        start, end = match.span()
+        if start > pos:
+            data = source[pos:start]
+            yield lineno, 'data', escape(escape_repl, data)
+            lineno += data.count('\n')
+        is_comment, is_code, cmd, args = match.groups()
+        if is_code:
+            yield lineno, 'code', args
+        elif not is_comment:
+            yield lineno, 'cmd', (cmd, args)
+        lineno += source[start:end].count('\n')
+        pos = end
+
+    if pos < len(source):
+        yield lineno, 'data', escape(escape_repl, source[pos:])
+
+
+def transform(node, filename):
+    root = ast.Module(None, node, lineno=1)
+    nodes = [root]
+    while nodes:
+        node = nodes.pop()
+        node.filename = filename
+        if node.__class__ in (ast.Printnl, ast.Print):
+            node.dest = ast.Name('__context')
+        elif node.__class__ is ast.Const and isinstance(node.value, str):
+            try:
+                node.value.decode('ascii')
+            except UnicodeError:
+                node.value = node.value.decode('utf-8')
+        nodes.extend(node.getChildNodes())
+    return root
+
+
+class TemplateSyntaxError(SyntaxError):
+
+    def __init__(self, msg, filename, lineno):
+        from linecache import getline
+        l = getline(filename, lineno)
+        SyntaxError.__init__(self, msg, (filename, lineno, len(l) or 1, l))
+
+
+class Parser(object):
+
+    def __init__(self, gen, filename):
+        self.gen = gen
+        self.filename = filename
+        self.lineno = 1
+
+    def fail(self, msg):
+        raise TemplateSyntaxError(msg, self.filename, self.lineno)
+
+    def parse_python(self, expr, type='exec'):
+        if isinstance(expr, unicode):
+            expr = '\xef\xbb\xbf' + expr.encode('utf-8')
+        try:
+            node = parse(expr, type)
+        except SyntaxError, e:
+            raise TemplateSyntaxError(str(e), self.filename,
+                                      self.lineno + e.lineno - 1)
+        nodes = [node]
+        while nodes:
+            n = nodes.pop()
+            if hasattr(n, 'lineno'):
+                n.lineno = (n.lineno or 1) + self.lineno - 1
+            nodes.extend(n.getChildNodes())
+        return node.node
+
+    def parse(self, needle=()):
+        start_lineno = self.lineno
+        result = []
+        add = result.append
+        for self.lineno, token, value in self.gen:
+            if token == 'data':
+                add(self.parse_data(value))
+            elif token == 'code':
+                add(self.parse_code(value.splitlines()))
+            elif token == 'cmd':
+                name, args = value
+                if name in needle:
+                    return name, args, ast.Stmt(result, lineno=start_lineno)
+                if name in ('for', 'while'):
+                    add(self.parse_loop(args, name))
+                elif name == 'if':
+                    add(self.parse_if(args))
+                else:
+                    self.fail('unknown directive %s' % name)
+        if needle:
+            self.fail('unexpected end of template')
+        return ast.Stmt(result, lineno=start_lineno)
+
+    def parse_loop(self, args, type):
+        rv = self.parse_python('%s %s: pass' % (type, args), 'exec').nodes[0]
+        tag, value, rv.body = self.parse(('end' + type, 'else'))
+        if value:
+            self.fail('unexpected data after ' + tag)
+        if tag == 'else':
+            tag, value, rv.else_ = self.parse(('end' + type,))
+            if value:
+                self.fail('unexpected data after else')
+        return rv
+
+    def parse_if(self, args):
+        cond = self.parse_python('if %s: pass' % args).nodes[0]
+        tag, value, body = self.parse(('else', 'elif', 'endif'))
+        cond.tests[0] = (cond.tests[0][0], body)
+        while 1:
+            if tag == 'else':
+                if value:
+                    self.fail('unexpected data after else')
+                tag, value, cond.else_ = self.parse(('endif',))
+            elif tag == 'elif':
+                expr = self.parse_python(value, 'eval')
+                tag, value, body = self.parse(('else', 'elif', 'endif'))
+                cond.tests.append((expr, body))
+                continue
+            break
+        if value:
+            self.fail('unexpected data after endif')
+        return cond
+
+    def parse_code(self, lines):
+        margin = sys.maxint
+        for line in lines[1:]:
+            content = len(line.lstrip())
+            if content:
+                indent = len(line) - content
+                margin = min(margin, indent)
+        if lines:
+            lines[0] = lines[0].lstrip()
+        if margin < sys.maxint:
+            for i in xrange(1, len(lines)):
+                lines[i] = lines[i][margin:]
+        while lines and not lines[-1]:
+            lines.pop()
+        while lines and not lines[0]:
+            lines.pop(0)
+        return self.parse_python('\n'.join(lines))
+
+    def parse_data(self, text):
+        start_lineno = lineno = self.lineno
+        pos = 0
+        end = len(text)
+        nodes = []
+
+        def match_or_fail(pos):
+            match = token_re.match(text, pos)
+            if match is None:
+                self.fail('invalid syntax')
+            return match.group().strip(), match.end()
+
+        def write_expr(code):
+            node = self.parse_python(code, 'eval')
+            nodes.append(call_stmt('__to_unicode', [node], lineno))
+            return code.count('\n')
+
+        def write_data(value):
+            if value:
+                nodes.append(ast.Const(value, lineno=lineno))
+                return value.count('\n')
+            return 0
+
+        while 1:
+            offset = text.find('$', pos)
+            if offset < 0:
+                break
+            next = text[offset + 1]
+
+            if next == '{':
+                lineno += write_data(text[pos:offset])
+                pos = offset + 2
+                level = 1
+                while level:
+                    token, pos = match_or_fail(pos)
+                    if token in ('{', '}'):
+                        level += token == '{' and 1 or -1
+                lineno += write_expr(text[offset + 2:pos - 1])
+            elif next in namestart_chars:
+                lineno += write_data(text[pos:offset])
+                token, pos = match_or_fail(offset + 1)
+                while pos < end:
+                    if text[pos] == '.' and pos + 1 < end and \
+                       text[pos + 1] in namestart_chars:
+                        token, pos = match_or_fail(pos + 1)
+                    elif text[pos] in '([':
+                        pos += 1
+                        level = 1
+                        while level:
+                            token, pos = match_or_fail(pos)
+                            if token in ('(', ')', '[', ']'):
+                                level += token in '([' and 1 or -1
+                    else:
+                        break
+                lineno += write_expr(text[offset + 1:pos])
+            else:
+                lineno += write_data(text[pos:offset + 1])
+                pos = offset + 1 + (next == '$')
+        write_data(text[pos:])
+
+        return ast.Discard(call_stmt(len(nodes) == 1 and '__write' or
+                           '__write_many', nodes, start_lineno),
+                           lineno=start_lineno)
+
+
+class Context(object):
+
+    def __init__(self, namespace, encoding, errors):
+        self.encoding = encoding
+        self.errors = errors
+        self._namespace = namespace
+        self._buffer = []
+        self._write = self._buffer.append
+        _extend = self._buffer.extend
+        self.runtime = dict(
+            Undefined=undefined,
+            __to_unicode=self.to_unicode,
+            __context=self,
+            __write=self._write,
+            __write_many=lambda *a: _extend(a)
+        )
+
+    def write(self, value):
+        self._write(self.to_unicode(value))
+
+    def to_unicode(self, value):
+        if isinstance(value, str):
+            return _decode_unicode(value, self.encoding, self.errors)
+        return unicode(value)
+
+    def get_value(self, as_unicode=True):
+        rv = u''.join(self._buffer)
+        if not as_unicode:
+            return rv.encode(self.encoding, self.errors)
+        return rv
+
+    def __getitem__(self, key, default=undefined):
+        try:
+            return self._namespace[key]
+        except KeyError:
+            return getattr(builtins, key, default)
+
+    def get(self, key, default=None):
+        return self.__getitem__(key, default)
+
+    def __setitem__(self, key, value):
+        self._namespace[key] = value
+
+    def __delitem__(self, key):
+        del self._namespace[key]
+
+
+class TemplateCodeGenerator(ModuleCodeGenerator):
+
+    def __init__(self, node, filename):
+        ModuleCodeGenerator.__init__(self, transform(node, filename))
+
+    def _nameOp(self, prefix, name):
+        if name in runtime_vars:
+            return self.emit(prefix + '_GLOBAL', name)
+        return ModuleCodeGenerator._nameOp(self, prefix, name)
+
+
+class Template(object):
+    """Represents a simple text based template.  It's a good idea to load such
+    templates from files on the file system to get better debug output.
+    """
+    default_context = {
+        'escape':           utils.escape,
+        'url_quote':        utils.url_quote,
+        'url_quote_plus':   utils.url_quote_plus,
+        'url_encode':       utils.url_encode
+    }
+
+    def __init__(self, source, filename='<template>', encoding='utf-8',
+                 errors='strict', unicode_mode=True):
+        if isinstance(source, str):
+            source = _decode_unicode(source, encoding, errors)
+        if isinstance(filename, unicode):
+            filename = filename.encode('utf-8')
+        node = Parser(tokenize(u'\n'.join(source.splitlines()),
+                               filename), filename).parse()
+        self.code = TemplateCodeGenerator(node, filename).getCode()
+        self.filename = filename
+        self.encoding = encoding
+        self.errors = errors
+        self.unicode_mode = unicode_mode
+
+    def from_file(cls, file, encoding='utf-8', errors='strict',
+                  unicode_mode=True):
+        """Load a template from a file."""
+        close = False
+        if isinstance(file, basestring):
+            f = open(file, 'r')
+            close = True
+        try:
+            data = _decode_unicode(f.read(), encoding, errors)
+        finally:
+            if close:
+                f.close()
+        return cls(data, getattr(f, 'name', '<template>'), encoding,
+                   errors, unicode_mode)
+    from_file = classmethod(from_file)
+
+    def render(self, *args, **kwargs):
+        """This function accepts either a dict or some keyword arguments which
+        will then be the context the template is evaluated in.  The return
+        value will be the rendered template.
+        """
+        ns = self.default_context.copy()
+        ns.update(dict(*args, **kwargs))
+        context = Context(ns, self.encoding, self.errors)
+        if sys.version_info < (2, 4):
+            exec self.code in context.runtime, ns
+        else:
+            exec self.code in context.runtime, context
+        return context.get_value(self.unicode_mode)
+
+    def substitute(self, *args, **kwargs):
+        """For API compatibility with `string.Template`."""
+        return self.render(*args, **kwargs)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/test.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,284 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.test
+    ~~~~~~~~~~~~~
+
+    Quite often you want to unittest your application or just check the output
+    from an interactive python session.  In theory that is pretty simple because
+    you can fake a WSGI environment and call the application with a dummy
+    start_response and iterate over the application iterator but there are
+    argumentably better ways to interact with an application.
+
+    Werkzeug provides an object called `Client` which you can pass a WSGI
+    application (and optionally a response wrapper) which you can use to send
+    virtual requests to the application.
+
+    A response wrapper is a callable that takes three arguments: the application
+    iterator, the status and finally a list of headers.  The default response
+    wrapper returns a tuple.  Because response objects have the same signature
+    you can use them as response wrapper, ideally by subclassing them and hooking
+    in test functionality.
+
+    >>> from werkzeug import Client, BaseResponse, test_app
+    >>> c = Client(test_app, BaseResponse)
+    >>> resp = c.get('/')
+    >>> resp.status_code
+    200
+    >>> resp.headers
+    Headers([('Content-Type', 'text/html; charset=utf-8')])
+    >>> resp.response_body.splitlines()[:2]
+    ['<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"',
+     '  "http://www.w3.org/TR/html4/loose.dtd">']
+
+    Or here without wrapper defined:
+
+    >>> from werkzeug import Client, test_app
+    >>> c = Client(test_app)
+    >>> app_iter, status, headers = c.get('/')
+    >>> status
+    '200 OK'
+    >>> headers
+    [('Content-Type', 'text/html; charset=utf-8')]
+    >>> ''.join(app_iter).splitlines()[:2]
+    ['<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"',
+     '  "http://www.w3.org/TR/html4/loose.dtd">']
+
+    :copyright: 2007 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+from time import time
+from random import random
+from urllib import urlencode
+from cStringIO import StringIO
+from mimetypes import guess_type
+from werkzeug.wrappers import BaseResponse
+from werkzeug.utils import create_environ, run_wsgi_app
+
+
+def encode_multipart(values):
+    """Encode a dict of values (can either be strings or file descriptors)
+    into a multipart encoded string.  The filename is taken from the `.name`
+    attribute of the file descriptor.  Because StringIOs do not provide
+    this attribute it will generate a random filename in that case.
+
+    The return value is a tuple in the form (``boundary``, ``data``).
+
+    This method does not accept unicode strings!
+    """
+    boundary = '-----------=_Part_%s%s' (time(), random())
+    lines = []
+    for key, value in values.iteritems():
+        if isinstance(value, File):
+            lines.extend((
+                '--' + boundary,
+                'Content-Disposition: form-data; name="%s"; filename="%s"' %
+                    (key, value.filename),
+                'Content-Type: ' + value.mimetype,
+                '',
+                value.read()
+            ))
+        else:
+            lines.extend((
+                '--' + boundary,
+                'Content-Disposition: form-data; name="%s"' % key,
+                '',
+                value
+            ))
+    lines.extend(('--' + boundary + '--', ''))
+    return boundary, '\r\n'.join(lines)
+
+
+class File(object):
+    """Wraps a file descriptor or any other stream so that `encode_multipart`
+    can get the mimetype and filename from it.
+    """
+
+    def __init__(self, fd, filename=None, mimetype=None):
+        if isinstance(fd, basestring):
+            if filename is None:
+                filename = fd
+            fd = file(fd, 'rb')
+            try:
+                self.stream = StringIO(fd.read())
+            finally:
+                fd.close()
+        else:
+            self.stream = fd
+            if filename is None:
+                if not hasattr(fd, 'name'):
+                    raise ValueError('no filename for provided')
+                filename = fd.name
+        if mimetype is None:
+            mimetype = guess_type(filename)
+        self.filename = fileanme
+        self.mimetype = mimetype or 'application/octet-stream'
+
+    def getattr(self, name):
+        return getattr(self.stream, name)
+
+    def __repr__(self):
+        return '<%s %r>' % (
+            self.__class__.__name__,
+            self.filename
+        )
+
+
+class Client(object):
+    """This class allows to send requests to a wrapped application."""
+
+    def __init__(self, application, response_wrapper=None):
+        """The response wrapper can be a class or factory function that takes
+        three arguments: app_iter, status and headers.  The default response
+        wrapper just returns a tuple.
+
+        Example::
+
+            class ClientResponse(BaseResponse):
+                ...
+
+            client = Client(MyApplication(), response_wrapper=ClientResponse)
+        """
+        self.application = application
+        if response_wrapper is None:
+            response_wrapper = lambda a, s, h: (a, s, h)
+        self.response_wrapper = response_wrapper
+
+    def open(self, path='/', base_url=None, query_string=None, method='GET',
+             data=None, input_stream=None, content_type=None,
+             content_length=0, errors_stream=None, multithread=False,
+             multiprocess=False, run_once=False, environ_overrides=None,
+             as_tuple=False):
+        """Takes the same arguments as the `create_environ` function from the
+        utility module with some additions.
+
+        The first parameter should be the path of the request which defaults to
+        '/'.  The second one can either be a absolute path (in that case the url
+        host is localhost:80) or a full path to the request with scheme,
+        netloc port and the path to the script.
+
+        If the `path` contains a query string it will be used, even if the
+        `query_string` parameter was given.  If it does not contain one
+        the `query_string` parameter is used as querystring.  In that case
+        it can either be a dict, MultiDict or string.
+
+        The following options exist:
+
+        `method`
+            The request method.  Defaults to `GET`
+
+        `input_stream`
+            The input stream.  Defaults to an empty read only stream.
+
+        `data`
+            The data you want to transmit.  You can set this to a string and
+            define a content type instead of specifying an input stream.
+            Additionally you can pass a dict with the form data.  The values
+            could then be strings (no unicode objects!) which are then url
+            encoded or file objects.
+
+            A file object for this method is either a file descriptor with
+            an additional `name` attribute (like a file descriptor returned
+            by the `open` / `file` function), a tuple in the form
+            ``(fd, filename, mimetype)`` (all arguments except fd optional)
+            or as dict with those keys and values.
+
+            Additionally you can instanciate the `werkzeug.test.File` object
+            (or a subclass of it) and pass it as value.
+
+        `content_type`
+            The content type for this request.  Default is an empty content
+            type.
+
+        `content_length`
+            The value for the content length header.  Defaults to 0.
+
+        `errors_stream`
+            The wsgi.errors stream.  Defaults to `sys.stderr`.
+
+        `multithread`
+            The multithreaded flag for the WSGI Environment.  Defaults to
+            `False`.
+
+        `multiprocess`
+            The multiprocess flag for the WSGI Environment.  Defaults to
+            `False`.
+
+        `run_once`
+            The run_once flag for the WSGI Environment.  Defaults to `False`.
+        """
+        if input_stream is None and data and method in ('PUT', 'POST'):
+            need_multipart = False
+            if isinstance(data, basestring):
+                assert content_type is not None, 'content type required'
+            else:
+                for key, value in data.iteritems():
+                    if isinstance(value, basestring):
+                        if isinstance(value, unicode):
+                            data[key] = str(value)
+                        continue
+                    need_multipart = True
+                    if isinstance(value, tuple):
+                        data[key] = File(*value)
+                    elif isinstance(value, dict):
+                        data[key] = File(**value)
+                    elif not isinstance(value, File):
+                        data[key] = File(value)
+                if need_multipart:
+                    boundary, data = encode_multipart(data)
+                    if content_type is None:
+                        content_type = 'multipart/form-data; boundary=' + \
+                            boundary
+                else:
+                    data = urlencode(data)
+                    if content_type is None:
+                        content_type = 'application/x-www-form-urlencoded'
+            content_length = len(data)
+            input_stream = StringIO(data)
+
+        if hasattr(path, 'environ'):
+            environ = path.environ
+        elif isinstance(path, dict):
+            environ = path
+        else:
+            environ = create_environ(path, base_url, query_string, method,
+                                     input_stream, content_type, content_length,
+                                     errors_stream, multithread,
+                                     multiprocess, run_once)
+        if environ_overrides:
+            environ.update(environ_overrides)
+        rv = run_wsgi_app(self.application, environ)
+        response = self.response_wrapper(*rv)
+        if as_tuple:
+            return environ, response
+        return response
+
+    def get(self, *args, **kw):
+        """Like open but method is enforced to GET"""
+        kw['method'] = 'GET'
+        return self.open(*args, **kw)
+
+    def post(self, *args, **kw):
+        """Like open but method is enforced to POST"""
+        kw['method'] = 'POST'
+        return self.open(*args, **kw)
+
+    def head(self, *args, **kw):
+        """Like open but method is enforced to HEAD"""
+        kw['method'] = 'HEAD'
+        return self.open(*args, **kw)
+
+    def put(self, *args, **kw):
+        """Like open but method is enforced to PUT"""
+        kw['method'] = 'PUT'
+        return self.open(*args, **kw)
+
+    def delete(self, *args, **kw):
+        """Like open but method is enforced to DELETE"""
+        kw['method'] = 'DELETE'
+        return self.open(*args, **kw)
+
+    def __repr__(self):
+        return '<%s %r>' % (
+            self.__class__.__name__,
+            self.application
+        )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/testapp.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,146 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.testapp
+    ~~~~~~~~~~~~~~~~
+
+    Provide a small test application that can be used to test a WSGI server
+    and check it for WSGI compliance.
+
+    :copyright: Copyright 2007-2008 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+from werkzeug.templates import Template
+from werkzeug.wrappers import BaseRequest as Request, BaseResponse as Response
+
+
+logo = Response('''R0lGODlhoACgAOMIAAEDACwpAEpCAGdgAJaKAM28AOnVAP3rAP/////////
+//////////////////////yH5BAEKAAgALAAAAACgAKAAAAT+EMlJq704680R+F0ojmRpnuj0rWnrv
+nB8rbRs33gu0bzu/0AObxgsGn3D5HHJbCUFyqZ0ukkSDlAidctNFg7gbI9LZlrBaHGtzAae0eloe25
+7w9EDOX2fst/xenyCIn5/gFqDiVVDV4aGeYiKkhSFjnCQY5OTlZaXgZp8nJ2ekaB0SQOjqphrpnOiq
+ncEn65UsLGytLVmQ6m4sQazpbtLqL/HwpnER8bHyLrLOc3Oz8PRONPU1crXN9na263dMt/g4SzjMeX
+m5yDpLqgG7OzJ4u8lT/P69ej3JPn69kHzN2OIAHkB9RUYSFCFQYQJFTIkCDBiwoXWGnowaLEjRm7+G
+p9A7Hhx4rUkAUaSLJlxHMqVMD/aSycSZkyTplCqtGnRAM5NQ1Ly5OmzZc6gO4d6DGAUKA+hSocWYAo
+SlM6oUWX2O/o0KdaVU5vuSQLAa0ADwQgMEMB2AIECZhVSnTno6spgbtXmHcBUrQACcc2FrTrWS8wAf
+78cMFBgwIBgbN+qvTt3ayikRBk7BoyGAGABAdYyfdzRQGV3l4coxrqQ84GpUBmrdR3xNIDUPAKDBSA
+ADIGDhhqTZIWaDcrVX8EsbNzbkvCOxG8bN5w8ly9H8jyTJHC6DFndQydbguh2e/ctZJFXRxMAqqPVA
+tQH5E64SPr1f0zz7sQYjAHg0In+JQ11+N2B0XXBeeYZgBZFx4tqBToiTCPv0YBgQv8JqA6BEf6RhXx
+w1ENhRBnWV8ctEX4Ul2zc3aVGcQNC2KElyTDYyYUWvShdjDyMOGMuFjqnII45aogPhz/CodUHFwaDx
+lTgsaOjNyhGWJQd+lFoAGk8ObghI0kawg+EV5blH3dr+digkYuAGSaQZFHFz2P/cTaLmhF52QeSb45
+Jwxd+uSVGHlqOZpOeJpCFZ5J+rkAkFjQ0N1tah7JJSZUFNsrkeJUJMIBi8jyaEKIhKPomnC91Uo+NB
+yyaJ5umnnpInIFh4t6ZSpGaAVmizqjpByDegYl8tPE0phCYrhcMWSv+uAqHfgH88ak5UXZmlKLVJhd
+dj78s1Fxnzo6yUCrV6rrDOkluG+QzCAUTbCwf9SrmMLzK6p+OPHx7DF+bsfMRq7Ec61Av9i6GLw23r
+idnZ+/OO0a99pbIrJkproCQMA17OPG6suq3cca5ruDfXCCDoS7BEdvmJn5otdqscn+uogRHHXs8cbh
+EIfYaDY1AkrC0cqwcZpnM6ludx72x0p7Fo/hZAcpJDjax0UdHavMKAbiKltMWCF3xxh9k25N/Viud8
+ba78iCvUkt+V6BpwMlErmcgc502x+u1nSxJSJP9Mi52awD1V4yB/QHONsnU3L+A/zR4VL/indx/y64
+gqcj+qgTeweM86f0Qy1QVbvmWH1D9h+alqg254QD8HJXHvjQaGOqEqC22M54PcftZVKVSQG9jhkv7C
+JyTyDoAJfPdu8v7DRZAxsP/ky9MJ3OL36DJfCFPASC3/aXlfLOOON9vGZZHydGf8LnxYJuuVIbl83y
+Az5n/RPz07E+9+zw2A2ahz4HxHo9Kt79HTMx1Q7ma7zAzHgHqYH0SoZWyTuOLMiHwSfZDAQTn0ajk9
+YQqodnUYjByQZhZak9Wu4gYQsMyEpIOAOQKze8CmEF45KuAHTvIDOfHJNipwoHMuGHBnJElUoDmAyX
+c2Qm/R8Ah/iILCCJOEokGowdhDYc/yoL+vpRGwyVSCWFYZNljkhEirGXsalWcAgOdeAdoXcktF2udb
+qbUhjWyMQxYO01o6KYKOr6iK3fE4MaS+DsvBsGOBaMb0Y6IxADaJhFICaOLmiWTlDAnY1KzDG4ambL
+cWBA8mUzjJsN2KjSaSXGqMCVXYpYkj33mcIApyhQf6YqgeNAmNvuC0t4CsDbSshZJkCS1eNisKqlyG
+cF8G2JeiDX6tO6Mv0SmjCa3MFb0bJaGPMU0X7c8XcpvMaOQmCajwSeY9G0WqbBmKv34DsMIEztU6Y2
+KiDlFdt6jnCSqx7Dmt6XnqSKaFFHNO5+FmODxMCWBEaco77lNDGXBM0ECYB/+s7nKFdwSF5hgXumQe
+EZ7amRg39RHy3zIjyRCykQh8Zo2iviRKyTDn/zx6EefptJj2Cw+Ep2FSc01U5ry4KLPYsTyWnVGnvb
+UpyGlhjBUljyjHhWpf8OFaXwhp9O4T1gU9UeyPPa8A2l0p1kNqPXEVRm1AOs1oAGZU596t6SOR2mcB
+Oco1srWtkaVrMUzIErrKri85keKqRQYX9VX0/eAUK1hrSu6HMEX3Qh2sCh0q0D2CtnUqS4hj62sE/z
+aDs2Sg7MBS6xnQeooc2R2tC9YrKpEi9pLXfYXp20tDCpSP8rKlrD4axprb9u1Df5hSbz9QU0cRpfgn
+kiIzwKucd0wsEHlLpe5yHXuc6FrNelOl7pY2+11kTWx7VpRu97dXA3DO1vbkhcb4zyvERYajQgAADs
+='''.decode('base64'), mimetype='image/png')
+
+
+TEMPLATE = Template(ur'''\
+<%py
+    import sys, os
+    from textwrap import wrap
+    try:
+        import pkg_resources
+    except ImportError:
+        eggs = None
+    else:
+        eggs = list(pkg_resources.working_set)
+        eggs.sort(lambda a, b: cmp(a.project_name.lower(),
+                                   b.project_name.lower()))
+    sorted_environ = req.environ.items()
+    sorted_environ.sort(lambda a, b: cmp(str(a[0]).lower(), str(b[0]).lower()))
+%>
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+  "http://www.w3.org/TR/html4/loose.dtd">
+<title>WSGI Information</title>
+<style type="text/css">
+  body      { font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
+              'Verdana', sans-serif; background-color: #AFC1C4; color: #000;
+              text-align: center; margin: 1em; padding: 0; }
+  #logo     { float: right; padding: 10px; }
+  div.box   { text-align: left; width: 45em; padding: 1em; margin: auto;
+              border: 1px solid #aaa; background-color: white; }
+  h1        { color: #11557C; font-size: 2em; margin: 0 0 0.8em 0; }
+  h2        { font-size: 1.4em; margin: 1em 0 0.5em 0; }
+  table     { width: 100%; border-collapse: collapse; border: 1px solid #AFC5C9 }
+  table th  { background-color: #AFC1C4; color: white; font-size: 0.72em;
+              font-weight: normal; width: 18em; vertical-align: top;
+              padding: 0.5em 0 0.1em 0.5em; }
+  table td  { border: 1px solid #AFC5C9; padding: 0.1em 0 0.1em 0.5em; }
+  code      { font-family: 'Consolas', 'Monaco', 'Bitstream Vera Sans Mono',
+              monospace; font-size: 0.7em; }
+  ul li     { line-height: 1.5em; }
+</style>
+<div class="box">
+  <img src="?resource=logo" id="logo" alt="[The Werkzeug Logo]" />
+  <h1>WSGI Information</h1>
+  <p>
+    This page displays all available information about the WSGI server and
+    the underlying Python interpreter that are available.
+  </p>
+  <h2 id="python-interpreter">Python Interpreter</h2>
+  <table>
+    <tr>
+      <th>Python Version</th>
+      <td>${'<br>'.join(escape(sys.version).splitlines())}</td>
+    </tr>
+    <tr>
+      <th>Platform</th>
+      <td>$escape(sys.platform) [$escape(os.name)]</td>
+    </tr>
+    <tr>
+      <th>API Version</th>
+      <td>$sys.api_version</td>
+    </tr>
+    <tr>
+      <th>Byteorder</th>
+      <td>$sys.byteorder</td>
+    </tr>
+  </table>
+  <h2 id="wsgi-environment">WSGI Environment</h2>
+  <table>
+  <% for key, value in sorted_environ %>
+    <tr>
+      <th>$escape(str(key))</th>
+      <td><code>${' '.join(wrap(escape(repr(value))))}</code></td>
+    </tr>
+  <% endfor %>
+  </table>
+  <% if eggs %>
+  <h2 id="installed-eggs">Installed Eggs</h2>
+  <ul>
+  <% for egg in eggs %>
+    <li>$escape(egg.project_name) <small>[$escape(egg.version)]</small></li>
+  <% endfor %>
+  </ul>
+  <% endif %>
+</div>''')
+
+
+def test_app(environ, start_response):
+    """Simple test application that dumps the environment."""
+    req = Request(environ, populate_request=False)
+    if req.args.get('resource') == 'logo':
+        response = logo
+    else:
+        response = Response(TEMPLATE.render(req=req), mimetype='text/html')
+    return response(environ, start_response)
+
+
+if __name__ == '__main__':
+    from werkzeug.serving import run_simple
+    run_simple('localhost', 5000, test_app, use_reloader=True)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/useragents.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,132 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.useragents
+    ~~~~~~~~~~~~~~~~~~~
+
+    This module provides a helper to inspect user agent strings.  This module
+    is far from complete but should work for most of the current browsers that
+    are available.
+
+
+    :copyright: 2007-2008 by Armin Ronacher.
+    :license: BSD, see LICENSE for more details.
+"""
+import re
+
+
+class UserAgentParser(object):
+    """A simple user agent parser.  Used by the `UserAgent`."""
+
+    platforms = (
+        (r'darwin|mac|os\s*x', 'macos'),
+        ('win', 'windows'),
+        (r'x11|lin(\b|ux)?', 'linux'),
+        ('(sun|i86)os', 'solaris'),
+        ('iphone', 'iphone'),
+        (r'nintendo\s+wii', 'wii'),
+        ('irix', 'irix'),
+        ('hp-?ux', 'hpux'),
+        ('aix', 'aix'),
+        ('sco|unix_sv', 'sco'),
+        ('bsd', 'bsd'),
+        ('amiga', 'amiga')
+    )
+    browsers = (
+        ('googlebot', 'google'),
+        ('msnbot', 'msn'),
+        ('yahoo', 'yahoo'),
+        ('ask jeeves', 'ask'),
+        (r'aol|america\s+online\s+browser', 'aol'),
+        ('opera', 'opera'),
+        ('firefox|firebird|phoenix|iceweasel', 'firefox'),
+        ('galeon', 'galeon'),
+        ('safari', 'safari'),
+        ('webkit', 'webkit'),
+        ('camino', 'camino'),
+        ('konqueror', 'konqueror'),
+        ('k-meleon', 'kmeleon'),
+        ('netscape', 'netscape'),
+        (r'msie|microsoft\s+internet\s+explorer', 'msie'),
+        ('lynx', 'lynx'),
+        ('links', 'links'),
+        ('seamonkey|mozilla', 'seamonkey')
+    )
+
+    _browser_version_re = r'(?:%s)[/\sa-z(]*(\d+[.\da-z]+)?(?i)'
+    _language_re = re.compile(
+        r'(?:;\s*|\s+)(\b\w{2}\b(?:-\b\w{2}\b)?)\s*;|'
+        r'(?:\(|\[|;)\s*(\b\w{2}\b(?:-\b\w{2}\b)?)\s*(?:\]|\)|;)'
+    )
+
+    def __init__(self):
+        self.platforms = re.compile(r'|'.join(['(?P<%s>%s)' % (b, a) for a, b
+                                    in self.platforms]), re.I)
+        self.browsers = [(b, re.compile(self._browser_version_re % a))
+                         for a, b in self.browsers]
+
+    def __call__(self, user_agent):
+        match = self.platforms.search(user_agent)
+        if match is not None:
+            for platform, value in match.groupdict().iteritems():
+                if value:
+                    break
+        else:
+            platform = None
+        for browser, regex in self.browsers:
+            match = regex.search(user_agent)
+            if match is not None:
+                version = match.group(1)
+                break
+        else:
+            browser = version = None
+        match = self._language_re.search(user_agent)
+        if match is not None:
+            language = match.group(1) or match.group(2)
+        else:
+            language = None
+        return platform, browser, version, language
+
+
+class UserAgent(object):
+    """Represents a user agent.  Pass it a WSGI environment or an user agent
+    string and you can inspect some of the details from the user agent
+    string via the attributes.  The following attribute exist:
+
+    -   `string`, the raw user agent string
+    -   `platform`, the browser platform
+    -   `browser`, the name of the browser
+    -   `version`, the version of the browser
+    -   `language`, the language of the browser
+    """
+    _parser = UserAgentParser()
+
+    def __init__(self, environ_or_string):
+        if isinstance(environ_or_string, dict):
+            environ_or_string = environ_or_string.get('HTTP_USER_AGENT', '')
+        self.string = environ_or_string
+        self.platform, self.browser, self.version, self.language = \
+            self._parser(environ_or_string)
+
+    def to_header(self):
+        return self.string
+
+    def __str__(self):
+        return self.string
+
+    def __nonzero__(self):
+        return bool(self.browser)
+
+    def __repr__(self):
+        return '<%s %r/%s>' % (
+            self.__class__.__name__,
+            self.browser,
+            self.version
+        )
+
+
+# conceptionally this belongs in this module but because we want to lazily
+# load the user agent module (which happens in wrappers.py) we have to import
+# it afterwards.  The class itself has the module set to this module so
+# pickle, inspect and similar modules treat the object as if it was really
+# implemented here.
+from werkzeug.wrappers import UserAgentMixin
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MoinMoin/support/werkzeug/utils.py	Wed Aug 13 21:05:42 2008 +0200
@@ -0,0 +1,1827 @@
+# -*- coding: utf-8 -*-
+"""
+    werkzeug.utils
+    ~~~~~~~~~~~~~~
+
+    This module implements various utilities for WSGI applications.  Most of
+    them are used by the request and response wrappers but especially for
+    middleware development it makes sense to use them without the wrappers.
+
+    :copyright: 2007-2008 by Armin Ronacher, Georg Brandl.
+    :license: BSD, see LICENSE for more details.
+"""
+import re
+import os
+import sys
+import cgi
+import urllib
+import urlparse
+import posixpath
+from itertools import chain
+from time import asctime, gmtime, time
+from datetime import timedelta
+try:
+    set = set
+except NameError:
+    from sets import Set as set
+    def reversed(item):
+        return item[::-1]
+from werkzeug._internal import _patch_wrapper, _decode_unicode, \
+     _empty_stream, _iter_modules, _ExtendedCookie, _ExtendedMorsel, \
+     _StorageHelper, _DictAccessorProperty, _dump_date, \
+     _parse_signature
+from werkzeug.http import generate_etag, parse_etags
+
+
+_format_re = re.compile(r'\$(%s|\{%s\})' % (('[a-zA-Z_][a-zA-Z0-9_]*',) * 2))
+_entity_re = re.compile(r'&([^;]+);')
+
+
+class MultiDict(dict):
+    """A `MultiDict` is a dictionary subclass customized to deal with multiple
+    values for the same key which is for example used by the parsing functions
+    in the wrappers.  This is necessary because some HTML form elements pass
+    multiple values for the same key.
+
+    `MultiDict` implements the all standard dictionary methods.  Internally,
+    it saves all values for a key as a list, but the standard dict access
+    methods will only return the first value for a key. If you want to gain
+    access to the other values too you have to use the `list` methods as
+    explained below.
+
+    Basic Usage:
+
+    >>> d = MultiDict([('a', 'b'), ('a', 'c')])
+    >>> d
+    MultiDict([('a', 'b'), ('a', 'c')])
+    >>> d['a']
+    'b'
+    >>> d.getlist('a')
+    ['b', 'c']
+    >>> 'a' in d
+    True
+
+    It behaves like a normal dict thus all dict functions will only return the
+    first value when multiple values for one key are found.
+
+    From Werkzeug 0.3 onwards, the `KeyError` raised by this class is also a
+    subclass of the `BadRequest` HTTP exception and will render a page for a
+    ``400 BAD REQUEST`` if catched in a catch-all for HTTP exceptions.
+    """
+
+    #: the key error this class raises.  Because of circular dependencies
+    #: with the http exception module this class is created at the end of
+    #: this module.
+    KeyError = None
+
+    def __init__(self, mapping=()):
+        """A `MultiDict` can be constructed from an iterable of
+        ``(key, value)`` tuples, a dict, a `MultiDict` or with Werkzeug 0.2
+        onwards some keyword parameters.
+        """
+        if isinstance(mapping, MultiDict):
+            dict.__init__(self, [(k, v[:]) for k, v in mapping.lists()])
+        elif isinstance(mapping, dict):
+            tmp = {}
+            for key, value in mapping.iteritems():
+                if isinstance(value, (tuple, list)):
+                    value = list(value)
+                else:
+                    value = [value]
+                tmp[key] = value
+            dict.__init__(self, tmp)
+        else:
+            tmp = {}
+            for key, value in mapping:
+                tmp.setdefault(key, []).append(value)
+            dict.__init__(self, tmp)
+
+    def __getitem__(self, key):
+        """Return the first data value for this key;
+        raises KeyError if not found.
+
+        :raise KeyError: if the key does not exist
+        """
+        if key in self:
+            return dict.__getitem__(self, key)[0]
+        raise self.KeyError(key)
+
+    def __setitem__(self, key, value):
+        """Set an item as list."""
+        dict.__setitem__(self, key, [value])
+
+    def get(self, key, default=None, type=None):
+        """Return the default value if the requested data doesn't exist.
+        If `type` is provided and is a callable it should convert the value,
+        return it or raise a `ValueError` if that is not possible.  In this
+        case the function will return the default as if the value was not
+        found.
+
+        Example:
+
+        >>> d = MultiDict(foo='42', bar='blub')
+        >>> d.get('foo', type=int)
+        42
+        >>> d.get('bar', -1, type=int)
+        -1
+        """
+        try:
+            rv = self[key]
+            if type is not None:
+                rv = type(rv)
+        except (KeyError, ValueError):
+            rv = default
+        return rv
+
+    def getlist(self, key, type=None):
+        """Return the list of items for a given key. If that key is not in the
+        `MultiDict`, the return value will be an empty list.  Just as `get`
+        `getlist` accepts a `type` parameter.  All items will be converted
+        with the callable defined there.
+
+        :return: list
+        """
+        try:
+            rv = dict.__getitem__(self, key)
+        except KeyError:
+            return []
+        if type is None:
+            return rv
+        result = []
+        for item in rv:
+            try:
+                result.append(type(item))
+            except ValueError:
+                pass
+        return result
+
+    def setlist(self, key, new_list):
+        """Remove the old values for a key and add new ones.  Note that the list
+        you pass the values in will be shallow-copied before it is inserted in
+        the dictionary.
+
+        >>> multidict.setlist('foo', ['1', '2'])
+        >>> multidict['foo']
+        '1'
+        >>> multidict.getlist('foo')
+        ['1', '2']
+        """
+        dict.__setitem__(self, key, list(new_list))
+
+    def setdefault(self, key, default=None):
+        if key not in self:
+            self[key] = default
+        else:
+            default = self[key]
+        return default
+
+    def setlistdefault(self, key, default_list=()):
+        """Like `setdefault` but sets multiple values."""
+        if key not in self:
+            default_list = list(default_list)
+            dict.__setitem__(self, key, default_list)
+        else:
+            default_list = self.getlist(key)
+        return default_list
+
+    def items(self):
+        """Return a list of (key, value) pairs, where value is the last item
+        in the list associated with the key.
+        """
+        return [(key, self[key]) for key in self.iterkeys()]
+
+    lists = dict.items
+
+    def values(self):
+        """Returns a list of the last value on every key list."""
+        return [self[key] for key in self.iterkeys()]
+
+    listvalues = dict.values
+
+    def iteritems(self):
+        for key, values in dict.iteritems(self):
+            yield key, values[0]
+
+    iterlists = dict.iteritems
+
+    def itervalues(self):
+        for values in dict.itervalues(self):
+            yield values[0]
+
+    iterlistvalues = dict.itervalues
+
+    def copy(self):
+        """Return a shallow copy of this object."""
+        return self.__class__(self)
+
+    def to_dict(self, flat=True):
+        """Return the contents as regular dict.  If `flat` is `True` the
+        returned dict will only have the first item present, if `flat` is
+        `False` all values will be returned as lists.
+
+        :return: dict
+        """
+        if flat:
+            return dict(self.iteritems())
+        return dict(self)
+
+    def update(self, other_dict):
+        """update() extends rather than replaces existing key lists."""
+        if isinstance(other_dict, MultiDict):
+            for key, value_list in other_dict.iterlists():
+                self.setlistdefault(key, []).extend(value_list)
+        elif isinstance(other_dict, dict):
+            for key, value in other_dict.items():
+                self.setlistdefault(key, []).append(value)
+        else:
+            for key, value in other_dict:
+                self.setlistdefault(key, []).append(value)
+
+    def pop(self, *args):
+        """Pop the first item for a list on the dict."""
+        return dict.pop(self, *args)[0]
+
+    def popitem(self):
+        """Pop an item from the dict."""
+        item = dict.popitem(self)
+        return (item[0], item[1][0])
+
+    poplist = dict.pop
+    popitemlist = dict.popitem
+
+    def __repr__(self):
+        tmp = []
+        for key, values in self.iterlists():
+            for value in values:
+                tmp.append((key, value))
+        return '%s(%r)' % (self.__class__.__name__, tmp)
+
+
+class CombinedMultiDict(MultiDict):
+    """A read only `MultiDict` decorator that you can pass multiple `MultiDict`
+    instances as sequence and it will combine the return values of all wrapped
+    dicts:
+
+    >>> from werkzeug import MultiDict, CombinedMultiDict
+    >>> post = MultiDict([('foo', 'bar')])
+    >>> get = MultiDict([('blub', 'blah')])
+    >>> combined = CombinedMultiDict([get, post])
+    >>> combined['foo']
+    'bar'
+    >>> combined['blub']
+    'blah'
+
+    This works for all read operations and will raise a `TypeError` for
+    methods that usually change data which isn't possible.
+
+    From Werkzeug 0.3 onwards, the `KeyError` raised by this class is also a
+    subclass of the `BadRequest` HTTP exception and will render a page for a
+    ``400 BAD REQUEST`` if catched in a catch-all for HTTP exceptions.
+    """
+
+    def __init__(self, dicts=None):
+        self.dicts = dicts or []
+
+    def fromkeys(cls):
+        raise TypeError('cannot create %r instances by fromkeys' %
+                        cls.__name__)
+    fromkeys = classmethod(fromkeys)
+
+    def __getitem__(self, key):
+        for d in self.dicts:
+            if key in d:
+                return d[key]
+        raise self.KeyError(key)
+
+    def get(self, key, default=None, type=None):
+        for d in self.dicts:
+            if key in d:
+                if type is not None:
+                    try:
+                        return type(d[key])
+                    except ValueError:
+                        continue
+                return d[key]
+        return default
+
+    def getlist(self, key, type=None):
+        rv = []
+        for d in self.dicts:
+            rv.extend(d.getlist(key, type))
+        return rv
+
+    def keys(self):
+        rv = set()
+        for d in self.dicts:
+            rv.update(d.keys())
+        return list(rv)
+
+    def iteritems(self):
+        found = set()
+        for d in self.dicts:
+            for key, value in d.iteritems():
+                if not key in found:
+                    found.add(key)
+                    yield key, value
+
+    def itervalues(self):
+        for key, value in self.iteritems():
+            yield value
+
+    def values(self):
+        return list(self.itervalues())
+
+    def items(self):
+        return list(self.iteritems())
+
+    def lists(self):
+        rv = {}
+        for d in self.dicts:
+            rv.update(d)
+        return rv.items()
+
+    def listvalues(self):
+        rv = {}
+        for d in reversed(self.dicts):
+            rv.update(d)
+        return rv.values()
+
+    def iterkeys(self):
+        return iter(self.keys())
+
+    __iter__ = iterkeys
+
+    def iterlists(self):
+        return iter(self.lists())
+
+    def iterlistvalues(self):
+        return iter(self.listvalues())
+
+    def copy(self):
+        """Return a shallow copy of this object."""
+        return self.__class__(self.dicts[:])
+
+    def to_dict(self, flat=True):
+        """Returns the contents as simple dict.  If `flat` is `True` the
+        resulting dict will only have the first item present, if `flat`
+        is `False` all values will be lists.
+        """
+        rv = {}
+        for d in reversed(self.dicts):
+            rv.update(d.to_dict(flat))
+        return rv
+
+    def _immutable(self, *args):
+        raise TypeError('%r instances are immutable' %
+                        self.__class__.__name__)
+
+    setlist = setdefault = setlistdefault = update = pop = popitem = \
+    poplist = popitemlist = __setitem__ = __delitem__ = _immutable
+    del _immutable
+
+    def __len__(self):
+        return len(self.keys())
+
+    def __contains__(self, key):
+        for d in self.dicts:
+            if key in d:
+                return True
+        return False
+
+    has_key = __contains__
+
+    def __repr__(self):
+        return '%s(%r)' % (self.__class__.__name__, self.dicts)
+
+
+class FileStorage(object):
+    """The `FileStorage` object is a thin wrapper over incoming files.  It is
+    used by the request object to represent uploaded files.  All the
+    attributes of the wrapper stream are proxied by the file storage so
+    it's possible to do ``storage.read()`` instead of the long form
+    ``storage.stream.read()``.
+    """
+
+    def __init__(self, stream=None, filename=None, name=None,
+                 content_type='application/octet-stream', content_length=-1):
+        """Creates a new `FileStorage` object.
+
+        :param stream: the input stream for uploaded file.  Usually this
+                       points to a temporary file.
+        :param filename: The filename of the file on the client.
+        :param name: the name of the form field
+        :param content_type: the content type of the file
+        :param content_length: the content length of the file.
+        """
+        self.name = name
+        self.stream = stream or _empty_stream
+        self.filename = filename or getattr(stream, 'name', None)
+        self.content_type = content_type
+        self.content_length = content_length
+
+    def save(self, dst, buffer_size=16384):
+        """Save the file to a destination path or file object.  If the
+        destination is a file object you have to close it yourself after the
+        call.  The buffer size is the number of bytes held in the memory
+        during the copy process.  It defaults to 16KB.
+        """
+        from shutil import copyfileobj
+        close_dst = False
+        if isinstance(dst, basestring):
+            dst = file(dst, 'wb')
+            close_dst = True
+        try:
+            copyfileobj(self.stream, dst, buffer_size)
+        finally:
+            if close_dst:
+                dst.close()
+
+    def __getattr__(self, name):
+        return getattr(self.stream, name)
+
+    def __nonzero__(self):
+        return bool(self.filename and self.content_length)
+
+    def __len__(self):
+        return max(self.content_length, 0)
+
+    def __iter__(self):
+        return iter(self.readline, '')
+
+    def __repr__(self):
+        return '<%s: %r (%r)>' % (
+            self.__class__.__name__,
+            self.filename,
+            self.content_type
+        )
+
+
+class Headers(object):
+    """An object that stores some headers.  It has a dict like interface
+    but is ordered and can store keys multiple times.
+
+    This data structure is useful if you want a nicer way to handle WSGI
+    headers which are stored as tuples in a list.
+
+    From Werkzeug 0.3 onwards, the `KeyError` raised by this class is also a
+    subclass of the `BadRequest` HTTP exception and will render a page for a
+    ``400 BAD REQUEST`` if catched in a catch-all for HTTP exceptions.
+    """
+
+    #: the key error this class raises.  Because of circular dependencies
+    #: with the http exception module this class is created at the end of
+    #: this module.
+    KeyError = None
+
+    def __init__(self, defaults=None, _list=None):
+        """Create a new `Headers` object based on a list or dict of headers
+        which are used as default values.  This does not reuse the list passed
+        to the constructor for internal usage.  To create a `Headers` object
+        that uses as internal storage the list or list-like object provided
+        it's possible to use the `linked` classmethod.
+        """
+        if _list is None:
+            _list = []
+        self._list = _list
+        if isinstance(defaults, dict):
+            for key, value in defaults.iteritems():
+                if isinstance(value, (tuple, list)):
+                    for v in value:
+                        self._list.append((key, v))
+                else:
+                    self._list.append((key, value))
+        elif defaults is not None:
+            self._list[:] = defaults
+
+    def linked(cls, headerlist):
+        """Create a new `Headers` object that uses the list of headers passed
+        as internal storage:
+
+        >>> headerlist = [('Content-Length', '40')]
+        >>> headers = Headers.linked(headerlist)
+        >>> headers.add('Content-Type', 'text/html')
+        >>> headerlist
+        [('Content-Length', '40'), ('Content-Type', 'text/html')]
+
+        :return: new linked `Headers` object.
+        """
+        return cls(_list=headerlist)
+    linked = classmethod(linked)
+
+    def __getitem__(self, key):
+        ikey = key.lower()
+        for k, v in self._list:
+            if k.lower() == ikey:
+                return v
+        raise self.KeyError(key)
+
+    def __eq__(self, other):
+        return other.__class__ is self.__class__ and \
+               set(other._list) == set(self._list)
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def get(self, key, default=None, type=None):
+        """Return the default value if the requested data doesn't exist.
+        If `type` is provided and is a callable it should convert the value,
+        return it or raise a `ValueError` if that is not possible.  In this
+        case the function will return the default as if the value was not
+        found.
+
+        Example:
+
+        >>> d = Headers([('Content-Length', '42')])
+        >>> d.get('Content-Length', type=int)
+        42
+
+        If a headers object is bound you must notadd unicode strings
+        because no encoding takes place.
+