constance

Scripts for generating (an earlier obsolete version of) my personal web site
git clone https://code.djc.id.au/git/constance/
commit 9d3c32538e054fbbc8f9963195124972480c89af
parent de6de8f177b0034015d492473267cc4245cf23af
Author: Dan Callaghan <djc@djc.id.au>
Date:   Sat, 11 Dec 2010 12:39:08 +1000

delete unused third-party code

Diffstat:
Dlib/Paste.egg-info/PKG-INFO | 119-------------------------------------------------------------------------------
Dlib/Paste.egg-info/SOURCES.txt | 233-------------------------------------------------------------------------------
Dlib/Paste.egg-info/dependency_links.txt | 1-
Dlib/Paste.egg-info/entry_points.txt | 47-----------------------------------------------
Dlib/Paste.egg-info/namespace_packages.txt | 1-
Dlib/Paste.egg-info/not-zip-safe | 1-
Dlib/Paste.egg-info/requires.txt | 15---------------
Dlib/Paste.egg-info/top_level.txt | 1-
Dlib/WebOb.egg-info/PKG-INFO | 23-----------------------
Dlib/WebOb.egg-info/SOURCES.txt | 51---------------------------------------------------
Dlib/WebOb.egg-info/dependency_links.txt | 1-
Dlib/WebOb.egg-info/top_level.txt | 1-
Dlib/WebOb.egg-info/zip-safe | 1-
Dlib/paste/__init__.py | 17-----------------
Dlib/paste/auth/__init__.py | 9---------
Dlib/paste/auth/auth_tkt.py | 352-------------------------------------------------------------------------------
Dlib/paste/auth/basic.py | 122-------------------------------------------------------------------------------
Dlib/paste/auth/cas.py | 99-------------------------------------------------------------------------------
Dlib/paste/auth/cookie.py | 395-------------------------------------------------------------------------------
Dlib/paste/auth/digest.py | 213-------------------------------------------------------------------------------
Dlib/paste/auth/form.py | 149-------------------------------------------------------------------------------
Dlib/paste/auth/grantip.py | 113-------------------------------------------------------------------------------
Dlib/paste/auth/multi.py | 79-------------------------------------------------------------------------------
Dlib/paste/auth/open_id.py | 412-------------------------------------------------------------------------------
Dlib/paste/cascade.py | 133-------------------------------------------------------------------------------
Dlib/paste/cgiapp.py | 271-------------------------------------------------------------------------------
Dlib/paste/cgitb_catcher.py | 116-------------------------------------------------------------------------------
Dlib/paste/config.py | 120-------------------------------------------------------------------------------
Dlib/paste/debug/__init__.py | 5-----
Dlib/paste/debug/debugapp.py | 79-------------------------------------------------------------------------------
Dlib/paste/debug/doctest_webapp.py | 435-------------------------------------------------------------------------------
Dlib/paste/debug/fsdiff.py | 409-------------------------------------------------------------------------------
Dlib/paste/debug/prints.py | 148-------------------------------------------------------------------------------
Dlib/paste/debug/profile.py | 227-------------------------------------------------------------------------------
Dlib/paste/debug/testserver.py | 93-------------------------------------------------------------------------------
Dlib/paste/debug/watchthreads.py | 347-------------------------------------------------------------------------------
Dlib/paste/debug/wdg_validate.py | 117-------------------------------------------------------------------------------
Dlib/paste/errordocument.py | 372-------------------------------------------------------------------------------
Dlib/paste/evalexception/__init__.py | 7-------
Dlib/paste/evalexception/evalcontext.py | 68--------------------------------------------------------------------
Dlib/paste/evalexception/media/debug.js | 161-------------------------------------------------------------------------------
Dlib/paste/evalexception/media/minus.jpg | 0
Dlib/paste/evalexception/media/plus.jpg | 0
Dlib/paste/evalexception/middleware.py | 611-------------------------------------------------------------------------------
Dlib/paste/evalexception/mochikit/MochiKit.js | 4802-------------------------------------------------------------------------------
Dlib/paste/evalexception/mochikit/__package__.js | 2--
Dlib/paste/exceptions/__init__.py | 6------
Dlib/paste/exceptions/collector.py | 526-------------------------------------------------------------------------------
Dlib/paste/exceptions/errormiddleware.py | 460-------------------------------------------------------------------------------
Dlib/paste/exceptions/formatter.py | 564-------------------------------------------------------------------------------
Dlib/paste/exceptions/reporter.py | 142-------------------------------------------------------------------------------
Dlib/paste/exceptions/serial_number_generator.py | 123-------------------------------------------------------------------------------
Dlib/paste/fileapp.py | 349-------------------------------------------------------------------------------
Dlib/paste/fixture.py | 1723-------------------------------------------------------------------------------
Dlib/paste/flup_session.py | 108-------------------------------------------------------------------------------
Dlib/paste/gzipper.py | 111-------------------------------------------------------------------------------
Dlib/paste/httpexceptions.py | 664-------------------------------------------------------------------------------
Dlib/paste/httpheaders.py | 1097-------------------------------------------------------------------------------
Dlib/paste/httpserver.py | 1406-------------------------------------------------------------------------------
Dlib/paste/lint.py | 436-------------------------------------------------------------------------------
Dlib/paste/modpython.py | 252-------------------------------------------------------------------------------
Dlib/paste/pony.py | 57---------------------------------------------------------
Dlib/paste/progress.py | 222-------------------------------------------------------------------------------
Dlib/paste/proxy.py | 276-------------------------------------------------------------------------------
Dlib/paste/recursive.py | 401-------------------------------------------------------------------------------
Dlib/paste/registry.py | 552-------------------------------------------------------------------------------
Dlib/paste/reloader.py | 178-------------------------------------------------------------------------------
Dlib/paste/request.py | 405-------------------------------------------------------------------------------
Dlib/paste/response.py | 240-------------------------------------------------------------------------------
Dlib/paste/session.py | 337-------------------------------------------------------------------------------
Dlib/paste/transaction.py | 120-------------------------------------------------------------------------------
Dlib/paste/translogger.py | 116-------------------------------------------------------------------------------
Dlib/paste/url.py | 475-------------------------------------------------------------------------------
Dlib/paste/urlmap.py | 251-------------------------------------------------------------------------------
Dlib/paste/urlparser.py | 652-------------------------------------------------------------------------------
Dlib/paste/util/PySourceColor.py | 2103-------------------------------------------------------------------------------
Dlib/paste/util/UserDict24.py | 167-------------------------------------------------------------------------------
Dlib/paste/util/__init__.py | 4----
Dlib/paste/util/classinit.py | 42------------------------------------------
Dlib/paste/util/classinstance.py | 38--------------------------------------
Dlib/paste/util/converters.py | 26--------------------------
Dlib/paste/util/dateinterval.py | 103-------------------------------------------------------------------------------
Dlib/paste/util/datetimeutil.py | 361-------------------------------------------------------------------------------
Dlib/paste/util/doctest24.py | 2665-------------------------------------------------------------------------------
Dlib/paste/util/filemixin.py | 53-----------------------------------------------------
Dlib/paste/util/finddata.py | 99-------------------------------------------------------------------------------
Dlib/paste/util/findpackage.py | 26--------------------------
Dlib/paste/util/import_string.py | 95-------------------------------------------------------------------------------
Dlib/paste/util/intset.py | 511-------------------------------------------------------------------------------
Dlib/paste/util/ip4.py | 273-------------------------------------------------------------------------------
Dlib/paste/util/killthread.py | 30------------------------------
Dlib/paste/util/looper.py | 152-------------------------------------------------------------------------------
Dlib/paste/util/mimeparse.py | 178-------------------------------------------------------------------------------
Dlib/paste/util/multidict.py | 397-------------------------------------------------------------------------------
Dlib/paste/util/quoting.py | 80-------------------------------------------------------------------------------
Dlib/paste/util/scgiserver.py | 172-------------------------------------------------------------------------------
Dlib/paste/util/string24.py | 531-------------------------------------------------------------------------------
Dlib/paste/util/subprocess24.py | 1152-------------------------------------------------------------------------------
Dlib/paste/util/template.py | 758-------------------------------------------------------------------------------
Dlib/paste/util/threadedprint.py | 250-------------------------------------------------------------------------------
Dlib/paste/util/threadinglocal.py | 43-------------------------------------------
Dlib/paste/wsgilib.py | 597-------------------------------------------------------------------------------
Dlib/paste/wsgiwrappers.py | 581-------------------------------------------------------------------------------
Dlib/recaptcha/__init__.py | 1-
Dlib/recaptcha/client/__init__.py | 0
Dlib/recaptcha/client/captcha.py | 92-------------------------------------------------------------------------------
Dlib/recaptcha/client/mailhide.py | 68--------------------------------------------------------------------
Dlib/smartypants.py | 903-------------------------------------------------------------------------------
Dlib/webob/__init__.py | 2383-------------------------------------------------------------------------------
Dlib/webob/acceptparse.py | 297-------------------------------------------------------------------------------
Dlib/webob/byterange.py | 295-------------------------------------------------------------------------------
Dlib/webob/cachecontrol.py | 169-------------------------------------------------------------------------------
Dlib/webob/compat.py | 23-----------------------
Dlib/webob/datastruct.py | 58----------------------------------------------------------
Dlib/webob/etag.py | 214-------------------------------------------------------------------------------
Dlib/webob/exc.py | 660-------------------------------------------------------------------------------
Dlib/webob/headerdict.py | 110-------------------------------------------------------------------------------
Dlib/webob/multidict.py | 606-------------------------------------------------------------------------------
Dlib/webob/statusreasons.py | 67-------------------------------------------------------------------
Dlib/webob/updatedict.py | 41-----------------------------------------
Dlib/webob/util/__init__.py | 1-
Dlib/webob/util/dictmixin.py | 102-------------------------------------------------------------------------------
Dlib/webob/util/reversed.py | 4----
Dlib/webob/util/safegzip.py | 21---------------------
Dlib/webob/util/stringtemplate.py | 128-------------------------------------------------------------------------------
125 files changed, 0 insertions(+), 40957 deletions(-)
diff --git a/lib/Paste.egg-info/PKG-INFO b/lib/Paste.egg-info/PKG-INFO
@@ -1,119 +0,0 @@
-Metadata-Version: 1.0
-Name: Paste
-Version: 1.7.2
-Summary: Tools for using a Web Server Gateway Interface stack
-Home-page: http://pythonpaste.org
-Author: Ian Bicking
-Author-email: ianb@colorstudy.com
-License: MIT
-Description: These provide several pieces of "middleware" (or filters) that can be nested to build web applications.  Each
-        piece of middleware uses the WSGI (`PEP 333`_) interface, and should
-        be compatible with other middleware based on those interfaces.
-        
-        .. _PEP 333: http://www.python.org/peps/pep-0333.html
-        
-        Includes these features...
-        
-        Testing
-        -------
-        
-        * A fixture for testing WSGI applications conveniently and in-process,
-        in ``paste.fixture``
-        
-        * A fixture for testing command-line applications, also in
-        ``paste.fixture``
-        
-        * Check components for WSGI-compliance in ``paste.lint``
-        
-        Dispatching
-        -----------
-        
-        * Chain and cascade WSGI applications (returning the first non-error
-        response) in ``paste.cascade``
-        
-        * Dispatch to several WSGI applications based on URL prefixes, in
-        ``paste.urlmap``
-        
-        * Allow applications to make subrequests and forward requests
-        internally, in ``paste.recursive``
-        
-        Web Application
-        ---------------
-        
-        * Run CGI programs as WSGI applications in ``paste.cgiapp``
-        
-        * Traverse files and load WSGI applications from ``.py`` files (or
-        static files), in ``paste.urlparser``
-        
-        * Serve static directories of files, also in ``paste.urlparser``; also
-        in that module serving from Egg resources using ``pkg_resources``.
-        
-        Tools
-        -----
-        
-        * Catch HTTP-related exceptions (e.g., ``HTTPNotFound``) and turn them
-        into proper responses in ``paste.httpexceptions``
-        
-        * Several authentication techniques, including HTTP (Basic and
-        Digest), signed cookies, and CAS single-signon, in the
-        ``paste.auth`` package.
-        
-        * Create sessions in ``paste.session`` and ``paste.flup_session``
-        
-        * Gzip responses in ``paste.gzip``
-        
-        * A wide variety of routines for manipulating WSGI requests and
-        producing responses, in ``paste.request``, ``paste.response`` and
-        ``paste.wsgilib``
-        
-        Debugging Filters
-        -----------------
-        
-        * Catch (optionally email) errors with extended tracebacks (using
-        Zope/ZPT conventions) in ``paste.exceptions``
-        
-        * Catch errors presenting a `cgitb
-        <http://python.org/doc/current/lib/module-cgitb.html>`_-based
-        output, in ``paste.cgitb_catcher``.
-        
-        * Profile each request and append profiling information to the HTML,
-        in ``paste.debug.profile``
-        
-        * Capture ``print`` output and present it in the browser for
-        debugging, in ``paste.debug.prints``
-        
-        * Validate all HTML output from applications using the `WDG Validator
-        <http://www.htmlhelp.com/tools/validator/>`_, appending any errors
-        or warnings to the page, in ``paste.debug.wdg_validator``
-        
-        Other Tools
-        -----------
-        
-        * A file monitor to allow restarting the server when files have been
-        updated (for automatic restarting when editing code) in
-        ``paste.reloader``
-        
-        * A class for generating and traversing URLs, and creating associated
-        HTML code, in ``paste.url``
-        
-        The latest version is available in a `Subversion repository
-        <http://svn.pythonpaste.org/Paste/trunk#egg=Paste-dev>`_.
-        
-        For the latest changes see the `news file
-        <http://pythonpaste.org/news.html>`_.
-        
-        
-Keywords: web application server wsgi
-Platform: UNKNOWN
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: MIT License
-Classifier: Programming Language :: Python
-Classifier: Topic :: Internet :: WWW/HTTP
-Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
-Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
-Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
-Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware
-Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Server
-Classifier: Framework :: Paste
diff --git a/lib/Paste.egg-info/SOURCES.txt b/lib/Paste.egg-info/SOURCES.txt
@@ -1,232 +0,0 @@
-regen-docs
-setup.cfg
-setup.py
-Paste.egg-info/PKG-INFO
-Paste.egg-info/SOURCES.txt
-Paste.egg-info/dependency_links.txt
-Paste.egg-info/entry_points.txt
-Paste.egg-info/namespace_packages.txt
-Paste.egg-info/not-zip-safe
-Paste.egg-info/requires.txt
-Paste.egg-info/top_level.txt
-docs/DeveloperGuidelines.txt
-docs/StyleGuide.txt
-docs/conf.py
-docs/default.css
-docs/developer-features.txt
-docs/do-it-yourself-framework.txt
-docs/future.txt
-docs/index.txt
-docs/license.txt
-docs/news.txt
-docs/paste-httpserver-threadpool.txt
-docs/test_server.ini
-docs/testing-applications.txt
-docs/url-parsing-with-wsgi.txt
-docs/_static/paste.css
-docs/_templates/layout.html
-docs/community/index.txt
-docs/community/mailing-list.txt
-docs/community/repository.txt
-docs/download/index.txt
-docs/include/contact.txt
-docs/include/reference_header.txt
-docs/modules/auth.auth_tkt.txt
-docs/modules/auth.basic.txt
-docs/modules/auth.cas.txt
-docs/modules/auth.cookie.txt
-docs/modules/auth.digest.txt
-docs/modules/auth.form.txt
-docs/modules/auth.grantip.txt
-docs/modules/auth.multi.txt
-docs/modules/auth.open_id.txt
-docs/modules/cascade.txt
-docs/modules/cgiapp.txt
-docs/modules/cgitb_catcher.txt
-docs/modules/debug.debugapp.txt
-docs/modules/debug.fsdiff.txt
-docs/modules/debug.prints.txt
-docs/modules/debug.profile.txt
-docs/modules/debug.watchthreads.txt
-docs/modules/debug.wdg_validate.txt
-docs/modules/errordocument.txt
-docs/modules/evalexception.txt
-docs/modules/exceptions.txt
-docs/modules/fileapp.txt
-docs/modules/fixture.txt
-docs/modules/gzipper.txt
-docs/modules/httpexceptions.txt
-docs/modules/httpheaders.txt
-docs/modules/httpserver.txt
-docs/modules/lint.txt
-docs/modules/pony.txt
-docs/modules/progress.txt
-docs/modules/proxy.txt
-docs/modules/recursive.txt
-docs/modules/registry.txt
-docs/modules/reloader.txt
-docs/modules/request.txt
-docs/modules/response.txt
-docs/modules/session.txt
-docs/modules/transaction.txt
-docs/modules/translogger.txt
-docs/modules/url.txt
-docs/modules/urlmap.txt
-docs/modules/urlparser.txt
-docs/modules/util.import_string.txt
-docs/modules/util.multidict.txt
-docs/modules/wsgilib.txt
-docs/modules/wsgiwrappers.txt
-docs/web/default-site.css
-docs/web/site.js
-docs/web/style.css
-paste/__init__.py
-paste/cascade.py
-paste/cgiapp.py
-paste/cgitb_catcher.py
-paste/config.py
-paste/errordocument.py
-paste/fileapp.py
-paste/fixture.py
-paste/flup_session.py
-paste/gzipper.py
-paste/httpexceptions.py
-paste/httpheaders.py
-paste/httpserver.py
-paste/lint.py
-paste/modpython.py
-paste/pony.py
-paste/progress.py
-paste/proxy.py
-paste/recursive.py
-paste/registry.py
-paste/reloader.py
-paste/request.py
-paste/response.py
-paste/session.py
-paste/transaction.py
-paste/translogger.py
-paste/url.py
-paste/urlmap.py
-paste/urlparser.py
-paste/wsgilib.py
-paste/wsgiwrappers.py
-paste/auth/__init__.py
-paste/auth/auth_tkt.py
-paste/auth/basic.py
-paste/auth/cas.py
-paste/auth/cookie.py
-paste/auth/digest.py
-paste/auth/form.py
-paste/auth/grantip.py
-paste/auth/multi.py
-paste/auth/open_id.py
-paste/debug/__init__.py
-paste/debug/debugapp.py
-paste/debug/doctest_webapp.py
-paste/debug/fsdiff.py
-paste/debug/prints.py
-paste/debug/profile.py
-paste/debug/testserver.py
-paste/debug/watchthreads.py
-paste/debug/wdg_validate.py
-paste/evalexception/__init__.py
-paste/evalexception/evalcontext.py
-paste/evalexception/middleware.py
-paste/evalexception/media/debug.js
-paste/evalexception/media/minus.jpg
-paste/evalexception/media/plus.jpg
-paste/evalexception/mochikit/MochiKit.js
-paste/evalexception/mochikit/__package__.js
-paste/exceptions/__init__.py
-paste/exceptions/collector.py
-paste/exceptions/errormiddleware.py
-paste/exceptions/formatter.py
-paste/exceptions/reporter.py
-paste/exceptions/serial_number_generator.py
-paste/util/PySourceColor.py
-paste/util/UserDict24.py
-paste/util/__init__.py
-paste/util/classinit.py
-paste/util/classinstance.py
-paste/util/converters.py
-paste/util/dateinterval.py
-paste/util/datetimeutil.py
-paste/util/doctest24.py
-paste/util/filemixin.py
-paste/util/finddata.py
-paste/util/findpackage.py
-paste/util/import_string.py
-paste/util/intset.py
-paste/util/ip4.py
-paste/util/killthread.py
-paste/util/looper.py
-paste/util/mimeparse.py
-paste/util/multidict.py
-paste/util/quoting.py
-paste/util/scgiserver.py
-paste/util/string24.py
-paste/util/subprocess24.py
-paste/util/template.py
-paste/util/threadedprint.py
-paste/util/threadinglocal.py
-tests/conftest.py
-tests/test_cgiapp.py
-tests/test_cgitb_catcher.py
-tests/test_config.py
-tests/test_doctests.py
-tests/test_errordocument.py
-tests/test_fileapp.py
-tests/test_fixture.py
-tests/test_grantip.py
-tests/test_gzipper.py
-tests/test_httpheaders.py
-tests/test_import_string.py
-tests/test_multidict.py
-tests/test_profilemiddleware.py
-tests/test_proxy.py
-tests/test_recursive.py
-tests/test_registry.py
-tests/test_request.py
-tests/test_request_form.py
-tests/test_response.py
-tests/test_session.py
-tests/test_template.txt
-tests/test_urlmap.py
-tests/test_urlparser.py
-tests/test_wsgiwrappers.py
-tests/cgiapp_data/error.cgi
-tests/cgiapp_data/form.cgi
-tests/cgiapp_data/ok.cgi
-tests/cgiapp_data/stderr.cgi
-tests/test_auth/test_auth_cookie.py
-tests/test_auth/test_auth_digest.py
-tests/test_exceptions/__init__.py
-tests/test_exceptions/test_error_middleware.py
-tests/test_exceptions/test_formatter.py
-tests/test_exceptions/test_httpexceptions.py
-tests/test_exceptions/test_reporter.py
-tests/test_util/test_datetimeutil.py
-tests/urlparser_data/__init__.py
-tests/urlparser_data/secured.txt
-tests/urlparser_data/deep/index.html
-tests/urlparser_data/deep/sub/Main.txt
-tests/urlparser_data/find_file/index.txt
-tests/urlparser_data/find_file/test 3.html
-tests/urlparser_data/find_file/test2.html
-tests/urlparser_data/find_file/dir with spaces/test 4.html
-tests/urlparser_data/hook/__init__.py
-tests/urlparser_data/hook/app.py
-tests/urlparser_data/hook/index.py
-tests/urlparser_data/not_found/__init__.py
-tests/urlparser_data/not_found/recur/__init__.py
-tests/urlparser_data/not_found/recur/isfound.txt
-tests/urlparser_data/not_found/simple/__init__.py
-tests/urlparser_data/not_found/simple/found.txt
-tests/urlparser_data/not_found/user/__init__.py
-tests/urlparser_data/not_found/user/list.py
-tests/urlparser_data/python/__init__.py
-tests/urlparser_data/python/simpleapp.py
-tests/urlparser_data/python/stream.py
-tests/urlparser_data/python/sub/__init__.py
-tests/urlparser_data/python/sub/simpleapp.py
-\ No newline at end of file
diff --git a/lib/Paste.egg-info/dependency_links.txt b/lib/Paste.egg-info/dependency_links.txt
@@ -1 +0,0 @@
-
diff --git a/lib/Paste.egg-info/entry_points.txt b/lib/Paste.egg-info/entry_points.txt
@@ -1,46 +0,0 @@
-
-      [paste.app_factory]
-      cgi = paste.cgiapp:make_cgi_application [subprocess]
-      static = paste.urlparser:make_static
-      pkg_resources = paste.urlparser:make_pkg_resources
-      urlparser = paste.urlparser:make_url_parser
-      proxy = paste.proxy:make_proxy
-      test = paste.debug.debugapp:make_test_app
-      test_slow = paste.debug.debugapp:make_slow_app
-      transparent_proxy = paste.proxy:make_transparent_proxy
-      watch_threads = paste.debug.watchthreads:make_watch_threads
-
-      [paste.composite_factory]
-      urlmap = paste.urlmap:urlmap_factory
-      cascade = paste.cascade:make_cascade
-
-      [paste.filter_app_factory]
-      error_catcher = paste.exceptions.errormiddleware:make_error_middleware
-      cgitb = paste.cgitb_catcher:make_cgitb_middleware
-      flup_session = paste.flup_session:make_session_middleware [Flup]
-      gzip = paste.gzipper:make_gzip_middleware
-      httpexceptions = paste.httpexceptions:make_middleware
-      lint = paste.lint:make_middleware
-      printdebug = paste.debug.prints:PrintDebugMiddleware 
-      profile = paste.debug.profile:make_profile_middleware [hotshot]
-      recursive = paste.recursive:make_recursive_middleware
-      # This isn't good enough to deserve the name egg:Paste#session:
-      paste_session = paste.session:make_session_middleware
-      wdg_validate = paste.debug.wdg_validate:make_wdg_validate_middleware [subprocess]
-      evalerror = paste.evalexception.middleware:make_eval_exception
-      auth_tkt = paste.auth.auth_tkt:make_auth_tkt_middleware
-      auth_basic = paste.auth.basic:make_basic
-      auth_digest = paste.auth.digest:make_digest
-      auth_form = paste.auth.form:make_form
-      grantip = paste.auth.grantip:make_grantip
-      openid = paste.auth.open_id:make_open_id_middleware [openid]
-      pony = paste.pony:make_pony
-      errordocument = paste.errordocument:make_errordocument
-      auth_cookie = paste.auth.cookie:make_auth_cookie
-      translogger = paste.translogger:make_filter
-      config = paste.config:make_config_filter
-      registry = paste.registry:make_registry_manager
-
-      [paste.server_runner]
-      http = paste.httpserver:server_runner
-      
-\ No newline at end of file
diff --git a/lib/Paste.egg-info/namespace_packages.txt b/lib/Paste.egg-info/namespace_packages.txt
@@ -1 +0,0 @@
-paste
diff --git a/lib/Paste.egg-info/not-zip-safe b/lib/Paste.egg-info/not-zip-safe
@@ -1 +0,0 @@
-
diff --git a/lib/Paste.egg-info/requires.txt b/lib/Paste.egg-info/requires.txt
@@ -1,15 +0,0 @@
-
-
-[Flup]
-flup
-
-[openid]
-python-openid
-
-[Paste]
-
-
-[hotshot]
-
-
-[subprocess]
diff --git a/lib/Paste.egg-info/top_level.txt b/lib/Paste.egg-info/top_level.txt
@@ -1 +0,0 @@
-paste
diff --git a/lib/WebOb.egg-info/PKG-INFO b/lib/WebOb.egg-info/PKG-INFO
@@ -1,23 +0,0 @@
-Metadata-Version: 1.0
-Name: WebOb
-Version: 0.9.4
-Summary: WSGI request and response object
-Home-page: http://pythonpaste.org/webob/
-Author: Ian Bicking
-Author-email: ianb@colorstudy.com
-License: MIT
-Description: WebOb provides wrappers around the WSGI request environment, and an
-        object to help create WSGI responses.
-        
-        The objects map much of the specified behavior of HTTP, including
-        header parsing and accessors for other standard parts of the
-        environment.
-        
-Keywords: wsgi request web http
-Platform: UNKNOWN
-Classifier: Development Status :: 4 - Beta
-Classifier: Framework :: Paste
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: MIT License
-Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
-Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
diff --git a/lib/WebOb.egg-info/SOURCES.txt b/lib/WebOb.egg-info/SOURCES.txt
@@ -1,50 +0,0 @@
-regen-docs
-setup.cfg
-setup.py
-test
-WebOb.egg-info/PKG-INFO
-WebOb.egg-info/SOURCES.txt
-WebOb.egg-info/dependency_links.txt
-WebOb.egg-info/top_level.txt
-WebOb.egg-info/zip-safe
-docs/comment-example.txt
-docs/conf.py
-docs/differences.txt
-docs/do-it-yourself.txt
-docs/file-example.txt
-docs/index.txt
-docs/jsonrpc-example.txt
-docs/license.txt
-docs/news.txt
-docs/reference.txt
-docs/test-file.txt
-docs/wiki-example.txt
-docs/comment-example-code/example.py
-docs/jsonrpc-example-code/jsonrpc.py
-docs/jsonrpc-example-code/test_jsonrpc.py
-docs/jsonrpc-example-code/test_jsonrpc.txt
-docs/modules/webob.txt
-docs/wiki-example-code/example.py
-tests/__init__.py
-tests/conftest.py
-tests/test_request.py
-tests/test_request.txt
-tests/test_response.py
-tests/test_response.txt
-webob/__init__.py
-webob/acceptparse.py
-webob/byterange.py
-webob/cachecontrol.py
-webob/compat.py
-webob/datastruct.py
-webob/etag.py
-webob/exc.py
-webob/headerdict.py
-webob/multidict.py
-webob/statusreasons.py
-webob/updatedict.py
-webob/util/__init__.py
-webob/util/dictmixin.py
-webob/util/reversed.py
-webob/util/safegzip.py
-webob/util/stringtemplate.py
-\ No newline at end of file
diff --git a/lib/WebOb.egg-info/dependency_links.txt b/lib/WebOb.egg-info/dependency_links.txt
@@ -1 +0,0 @@
-
diff --git a/lib/WebOb.egg-info/top_level.txt b/lib/WebOb.egg-info/top_level.txt
@@ -1 +0,0 @@
-webob
diff --git a/lib/WebOb.egg-info/zip-safe b/lib/WebOb.egg-info/zip-safe
@@ -1 +0,0 @@
-
diff --git a/lib/paste/__init__.py b/lib/paste/__init__.py
@@ -1,17 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-try:
-    import pkg_resources
-    pkg_resources.declare_namespace(__name__)
-except ImportError:
-    # don't prevent use of paste if pkg_resources isn't installed
-    from pkgutil import extend_path
-    __path__ = extend_path(__path__, __name__) 
-
-try:
-    import modulefinder
-except ImportError:
-    pass
-else:
-    for p in __path__:
-        modulefinder.AddPackagePath(__name__, p)
diff --git a/lib/paste/auth/__init__.py b/lib/paste/auth/__init__.py
@@ -1,9 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-Package for authentication/identification of requests.
-
-The objective of this package is to provide single-focused middleware
-components that implement a particular specification.  Integration of
-the components into a usable system is up to a higher-level framework.
-"""
diff --git a/lib/paste/auth/auth_tkt.py b/lib/paste/auth/auth_tkt.py
@@ -1,352 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-##########################################################################
-#
-# Copyright (c) 2005 Imaginary Landscape LLC and Contributors.
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-##########################################################################
-"""
-Implementation of cookie signing as done in `mod_auth_tkt
-<http://www.openfusion.com.au/labs/mod_auth_tkt/>`_.
-
-mod_auth_tkt is an Apache module that looks for these signed cookies
-and sets ``REMOTE_USER``, ``REMOTE_USER_TOKENS`` (a comma-separated
-list of groups) and ``REMOTE_USER_DATA`` (arbitrary string data).
-
-This module is an alternative to the ``paste.auth.cookie`` module;
-it's primary benefit is compatibility with mod_auth_tkt, which in turn
-makes it possible to use the same authentication process with
-non-Python code run under Apache.
-"""
-
-import time as time_mod
-try:
-    from hashlib import md5
-except ImportError:
-    from md5 import md5
-import Cookie
-from paste import request
-
-class AuthTicket(object):
-
-    """
-    This class represents an authentication token.  You must pass in
-    the shared secret, the userid, and the IP address.  Optionally you
-    can include tokens (a list of strings, representing role names),
-    'user_data', which is arbitrary data available for your own use in
-    later scripts.  Lastly, you can override the cookie name and
-    timestamp.
-
-    Once you provide all the arguments, use .cookie_value() to
-    generate the appropriate authentication ticket.  .cookie()
-    generates a Cookie object, the str() of which is the complete
-    cookie header to be sent.
-
-    CGI usage::
-
-        token = auth_tkt.AuthTick('sharedsecret', 'username',
-            os.environ['REMOTE_ADDR'], tokens=['admin'])
-        print 'Status: 200 OK'
-        print 'Content-type: text/html'
-        print token.cookie()
-        print
-        ... redirect HTML ...
-
-    Webware usage::
-
-        token = auth_tkt.AuthTick('sharedsecret', 'username',
-            self.request().environ()['REMOTE_ADDR'], tokens=['admin'])
-        self.response().setCookie('auth_tkt', token.cookie_value())
-
-    Be careful not to do an HTTP redirect after login; use meta
-    refresh or Javascript -- some browsers have bugs where cookies
-    aren't saved when set on a redirect.
-    """
-
-    def __init__(self, secret, userid, ip, tokens=(), user_data='',
-                 time=None, cookie_name='auth_tkt',
-                 secure=False):
-        self.secret = secret
-        self.userid = userid
-        self.ip = ip
-        self.tokens = ','.join(tokens)
-        self.user_data = user_data
-        if time is None:
-            self.time = time_mod.time()
-        else:
-            self.time = time
-        self.cookie_name = cookie_name
-        self.secure = secure
-
-    def digest(self):
-        return calculate_digest(
-            self.ip, self.time, self.secret, self.userid, self.tokens,
-            self.user_data)
-
-    def cookie_value(self):
-        v = '%s%08x%s!' % (self.digest(), int(self.time), self.userid)
-        if self.tokens:
-            v += self.tokens + '!'
-        v += self.user_data
-        return v
-
-    def cookie(self):
-        c = Cookie.SimpleCookie()
-        c[self.cookie_name] = self.cookie_value().encode('base64').strip().replace('\n', '')
-        c[self.cookie_name]['path'] = '/'
-        if self.secure:
-            c[self.cookie_name]['secure'] = 'true'
-        return c
-
-class BadTicket(Exception):
-    """
-    Exception raised when a ticket can't be parsed.  If we get
-    far enough to determine what the expected digest should have
-    been, expected is set.  This should not be shown by default,
-    but can be useful for debugging.
-    """
-    def __init__(self, msg, expected=None):
-        self.expected = expected
-        Exception.__init__(self, msg)
-
-def parse_ticket(secret, ticket, ip):
-    """
-    Parse the ticket, returning (timestamp, userid, tokens, user_data).
-
-    If the ticket cannot be parsed, ``BadTicket`` will be raised with
-    an explanation.
-    """
-    ticket = ticket.strip('"')
-    digest = ticket[:32]
-    try:
-        timestamp = int(ticket[32:40], 16)
-    except ValueError, e:
-        raise BadTicket('Timestamp is not a hex integer: %s' % e)
-    try:
-        userid, data = ticket[40:].split('!', 1)
-    except ValueError:
-        raise BadTicket('userid is not followed by !')
-    if '!' in data:
-        tokens, user_data = data.split('!', 1)
-    else:
-        # @@: Is this the right order?
-        tokens = ''
-        user_data = data
-    
-    expected = calculate_digest(ip, timestamp, secret,
-                                userid, tokens, user_data)
-
-    if expected != digest:
-        raise BadTicket('Digest signature is not correct',
-                        expected=(expected, digest))
-
-    tokens = tokens.split(',')
-
-    return (timestamp, userid, tokens, user_data)
-    
-def calculate_digest(ip, timestamp, secret, userid, tokens, user_data):
-    secret = maybe_encode(secret)
-    userid = maybe_encode(userid)
-    tokens = maybe_encode(tokens)
-    user_data = maybe_encode(user_data)
-    digest0 = md5(
-        encode_ip_timestamp(ip, timestamp) + secret + userid + '\0'
-        + tokens + '\0' + user_data).hexdigest()
-    digest = md5(digest0 + secret).hexdigest()
-    return digest
-
-def encode_ip_timestamp(ip, timestamp):
-    ip_chars = ''.join(map(chr, map(int, ip.split('.'))))
-    t = int(timestamp)
-    ts = ((t & 0xff000000) >> 24,
-          (t & 0xff0000) >> 16,
-          (t & 0xff00) >> 8,
-          t & 0xff)
-    ts_chars = ''.join(map(chr, ts))
-    return ip_chars + ts_chars
-
-def maybe_encode(s, encoding='utf8'):
-    if isinstance(s, unicode):
-        s = s.encode(encoding)
-    return s
-
-class AuthTKTMiddleware(object):
-
-    """
-    Middleware that checks for signed cookies that match what
-    `mod_auth_tkt <http://www.openfusion.com.au/labs/mod_auth_tkt/>`_
-    looks for (if you have mod_auth_tkt installed, you don't need this
-    middleware, since Apache will set the environmental variables for
-    you).
-
-    Arguments:
-    
-    ``secret``:
-        A secret that should be shared by any instances of this application.
-        If this app is served from more than one machine, they should all 
-        have the same secret.
-        
-    ``cookie_name``:
-        The name of the cookie to read and write from.  Default ``auth_tkt``.
-        
-    ``secure``:
-        If the cookie should be set as 'secure' (only sent over SSL) and if
-        the login must be over SSL.
-        
-    ``include_ip``:
-        If the cookie should include the user's IP address.  If so, then 
-        if they change IPs their cookie will be invalid.
-        
-    ``logout_path``:
-        The path under this middleware that should signify a logout.  The
-        page will be shown as usual, but the user will also be logged out
-        when they visit this page.
-        
-    If used with mod_auth_tkt, then these settings (except logout_path) should 
-    match the analogous Apache configuration settings.
-
-    This also adds two functions to the request:
-
-    ``environ['paste.auth_tkt.set_user'](userid, tokens='', user_data='')``
-
-        This sets a cookie that logs the user in.  ``tokens`` is a
-        string (comma-separated groups) or a list of strings.
-        ``user_data`` is a string for your own use.
-
-    ``environ['paste.auth_tkt.logout_user']()``
-
-        Logs out the user.
-    """
-
-    def __init__(self, app, secret, cookie_name='auth_tkt', secure=False,
-                 include_ip=True, logout_path=None):
-        self.app = app
-        self.secret = secret
-        self.cookie_name = cookie_name
-        self.secure = secure
-        self.include_ip = include_ip
-        self.logout_path = logout_path
-
-    def __call__(self, environ, start_response):
-        cookies = request.get_cookies(environ)
-        if cookies.has_key(self.cookie_name):
-            cookie_value = cookies[self.cookie_name].value
-        else:
-            cookie_value = ''
-        if cookie_value:
-            if self.include_ip:
-                remote_addr = environ['REMOTE_ADDR']
-            else:
-                # mod_auth_tkt uses this dummy value when IP is not
-                # checked:
-                remote_addr = '0.0.0.0'
-            # @@: This should handle bad signatures better:
-            # Also, timeouts should cause cookie refresh
-            timestamp, userid, tokens, user_data = parse_ticket(
-                self.secret, cookie_value, remote_addr)
-            tokens = ','.join(tokens)
-            environ['REMOTE_USER'] = userid
-            if environ.get('REMOTE_USER_TOKENS'):
-                # We want to add tokens/roles to what's there:
-                tokens = environ['REMOTE_USER_TOKENS'] + ',' + tokens
-            environ['REMOTE_USER_TOKENS'] = tokens
-            environ['REMOTE_USER_DATA'] = user_data
-            environ['AUTH_TYPE'] = 'cookie'
-        set_cookies = []
-        def set_user(userid, tokens='', user_data=''):
-            set_cookies.extend(self.set_user_cookie(
-                environ, userid, tokens, user_data))
-        def logout_user():
-            set_cookies.extend(self.logout_user_cookie(environ))
-        environ['paste.auth_tkt.set_user'] = set_user
-        environ['paste.auth_tkt.logout_user'] = logout_user
-        if self.logout_path and environ.get('PATH_INFO') == self.logout_path:
-            logout_user()
-        def cookie_setting_start_response(status, headers, exc_info=None):
-            headers.extend(set_cookies)
-            return start_response(status, headers, exc_info)
-        return self.app(environ, cookie_setting_start_response)
-
-    def set_user_cookie(self, environ, userid, tokens, user_data):
-        if not isinstance(tokens, basestring):
-            tokens = ','.join(tokens)
-        if self.include_ip:
-            remote_addr = environ['REMOTE_ADDR']
-        else:
-            remote_addr = '0.0.0.0'
-        ticket = AuthTicket(
-            self.secret,
-            userid,
-            remote_addr,
-            tokens=tokens,
-            user_data=user_data,
-            cookie_name=self.cookie_name,
-            secure=self.secure)
-        # @@: Should we set REMOTE_USER etc in the current
-        # environment right now as well?
-        cur_domain = environ.get('HTTP_HOST', environ.get('SERVER_NAME'))
-        wild_domain = '.' + cur_domain
-        cookies = [
-            ('Set-Cookie', '%s=%s; Path=/' % (
-            self.cookie_name, ticket.cookie_value())),
-            ('Set-Cookie', '%s=%s; Path=/; Domain=%s' % (
-            self.cookie_name, ticket.cookie_value(), cur_domain)),
-            ('Set-Cookie', '%s=%s; Path=/; Domain=%s' % (
-            self.cookie_name, ticket.cookie_value(), wild_domain))
-            ]
-        return cookies
-    
-    def logout_user_cookie(self, environ):
-        cur_domain = environ.get('HTTP_HOST', environ.get('SERVER_NAME'))
-        wild_domain = '.' + cur_domain
-        cookies = [
-            ('Set-Cookie', '%s=""; Path=/' % self.cookie_name),
-            ('Set-Cookie', '%s=""; Path=/; Domain=%s' %
-             (self.cookie_name, cur_domain)),
-            ('Set-Cookie', '%s=""; Path=/; Domain=%s' %
-             (self.cookie_name, wild_domain)),
-            ]
-        return cookies
-
-def make_auth_tkt_middleware(
-    app,
-    global_conf,
-    secret=None,
-    cookie_name='auth_tkt',
-    secure=False,
-    include_ip=True,
-    logout_path=None):
-    """
-    Creates the `AuthTKTMiddleware
-    <class-paste.auth.auth_tkt.AuthTKTMiddleware.html>`_.
-
-    ``secret`` is requird, but can be set globally or locally.
-    """
-    from paste.deploy.converters import asbool
-    secure = asbool(secure)
-    include_ip = asbool(include_ip)
-    if secret is None:
-        secret = global_conf.get('secret')
-    if not secret:
-        raise ValueError(
-            "You must provide a 'secret' (in global or local configuration)")
-    return AuthTKTMiddleware(
-        app, secret, cookie_name, secure, include_ip, logout_path or None)
diff --git a/lib/paste/auth/basic.py b/lib/paste/auth/basic.py
@@ -1,122 +0,0 @@
-# (c) 2005 Clark C. Evans
-# This module is part of the Python Paste Project and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-# This code was written with funding by http://prometheusresearch.com
-"""
-Basic HTTP/1.0 Authentication
-
-This module implements ``Basic`` authentication as described in
-HTTP/1.0 specification [1]_ .  Do not use this module unless you
-are using SSL or need to work with very out-dated clients, instead
-use ``digest`` authentication.
-
->>> from paste.wsgilib import dump_environ
->>> from paste.httpserver import serve
->>> # from paste.auth.basic import AuthBasicHandler
->>> realm = 'Test Realm'
->>> def authfunc(environ, username, password):
-...     return username == password
->>> serve(AuthBasicHandler(dump_environ, realm, authfunc))
-serving on...
-
-.. [1] http://www.w3.org/Protocols/HTTP/1.0/draft-ietf-http-spec.html#BasicAA
-"""
-from paste.httpexceptions import HTTPUnauthorized
-from paste.httpheaders import *
-
-class AuthBasicAuthenticator(object):
-    """
-    implements ``Basic`` authentication details
-    """
-    type = 'basic'
-    def __init__(self, realm, authfunc):
-        self.realm = realm
-        self.authfunc = authfunc
-
-    def build_authentication(self):
-        head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
-        return HTTPUnauthorized(headers=head)
-
-    def authenticate(self, environ):
-        authorization = AUTHORIZATION(environ)
-        if not authorization:
-            return self.build_authentication()
-        (authmeth, auth) = authorization.split(' ', 1)
-        if 'basic' != authmeth.lower():
-            return self.build_authentication()
-        auth = auth.strip().decode('base64')
-        username, password = auth.split(':', 1)
-        if self.authfunc(environ, username, password):
-            return username
-        return self.build_authentication()
-
-    __call__ = authenticate
-
-class AuthBasicHandler(object):
-    """
-    HTTP/1.0 ``Basic`` authentication middleware
-
-    Parameters:
-
-        ``application``
-
-            The application object is called only upon successful
-            authentication, and can assume ``environ['REMOTE_USER']``
-            is set.  If the ``REMOTE_USER`` is already set, this
-            middleware is simply pass-through.
-
-        ``realm``
-
-            This is a identifier for the authority that is requesting
-            authorization.  It is shown to the user and should be unique
-            within the domain it is being used.
-
-        ``authfunc``
-
-            This is a mandatory user-defined function which takes a
-            ``environ``, ``username`` and ``password`` for its first
-            three arguments.  It should return ``True`` if the user is
-            authenticated.
-
-    """
-    def __init__(self, application, realm, authfunc):
-        self.application = application
-        self.authenticate = AuthBasicAuthenticator(realm, authfunc)
-
-    def __call__(self, environ, start_response):
-        username = REMOTE_USER(environ)
-        if not username:
-            result = self.authenticate(environ)
-            if isinstance(result, str):
-                AUTH_TYPE.update(environ, 'basic')
-                REMOTE_USER.update(environ, result)
-            else:
-                return result.wsgi_application(environ, start_response)
-        return self.application(environ, start_response)
-
-middleware = AuthBasicHandler
-
-__all__ = ['AuthBasicHandler']
-
-def make_basic(app, global_conf, realm, authfunc, **kw):
-    """
-    Grant access via basic authentication
-
-    Config looks like this::
-
-      [filter:grant]
-      use = egg:Paste#auth_basic
-      realm=myrealm
-      authfunc=somepackage.somemodule:somefunction
-      
-    """
-    from paste.util.import_string import eval_import
-    import types
-    authfunc = eval_import(authfunc)
-    assert isinstance(authfunc, types.FunctionType), "authfunc must resolve to a function"
-    return AuthBasicHandler(app, realm, authfunc)
-    
-
-if "__main__" == __name__:
-    import doctest
-    doctest.testmod(optionflags=doctest.ELLIPSIS)
diff --git a/lib/paste/auth/cas.py b/lib/paste/auth/cas.py
@@ -1,99 +0,0 @@
-# (c) 2005 Clark C. Evans
-# This module is part of the Python Paste Project and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-# This code was written with funding by http://prometheusresearch.com
-"""
-CAS 1.0 Authentication
-
-The Central Authentication System is a straight-forward single sign-on
-mechanism developed by Yale University's ITS department.  It has since
-enjoyed widespread success and is deployed at many major universities
-and some corporations.
-
-    https://clearinghouse.ja-sig.org/wiki/display/CAS/Home
-    http://www.yale.edu/tp/auth/usingcasatyale.html
-
-This implementation has the goal of maintaining current path arguments
-passed to the system so that it can be used as middleware at any stage
-of processing.  It has the secondary goal of allowing for other
-authentication methods to be used concurrently.
-"""
-import urllib
-from paste.request import construct_url
-from paste.httpexceptions import HTTPSeeOther, HTTPForbidden
-
-class CASLoginFailure(HTTPForbidden):
-    """ The exception raised if the authority returns 'no' """
-
-class CASAuthenticate(HTTPSeeOther):
-    """ The exception raised to authenticate the user """
-
-def AuthCASHandler(application, authority):
-    """
-    middleware to implement CAS 1.0 authentication
-
-    There are several possible outcomes:
-
-    0. If the REMOTE_USER environment variable is already populated;
-       then this middleware is a no-op, and the request is passed along
-       to the application.
-
-    1. If a query argument 'ticket' is found, then an attempt to
-       validate said ticket /w the authentication service done.  If the
-       ticket is not validated; an 403 'Forbidden' exception is raised.
-       Otherwise, the REMOTE_USER variable is set with the NetID that
-       was validated and AUTH_TYPE is set to "cas".
-
-    2. Otherwise, a 303 'See Other' is returned to the client directing
-       them to login using the CAS service.  After logon, the service
-       will send them back to this same URL, only with a 'ticket' query
-       argument.
-
-    Parameters:
-
-        ``authority``
-
-            This is a fully-qualified URL to a CAS 1.0 service. The URL
-            should end with a '/' and have the 'login' and 'validate'
-            sub-paths as described in the CAS 1.0 documentation.
-
-    """
-    assert authority.endswith("/") and authority.startswith("http")
-    def cas_application(environ, start_response):
-        username = environ.get('REMOTE_USER','')
-        if username:
-            return application(environ, start_response)
-        qs = environ.get('QUERY_STRING','').split("&")
-        if qs and qs[-1].startswith("ticket="):
-            # assume a response from the authority
-            ticket = qs.pop().split("=", 1)[1]
-            environ['QUERY_STRING'] = "&".join(qs)
-            service = construct_url(environ)
-            args = urllib.urlencode(
-                    {'service': service,'ticket': ticket})
-            requrl = authority + "validate?" + args
-            result = urllib.urlopen(requrl).read().split("\n")
-            if 'yes' == result[0]:
-                environ['REMOTE_USER'] = result[1]
-                environ['AUTH_TYPE'] = 'cas'
-                return application(environ, start_response)
-            exce = CASLoginFailure()
-        else:
-            service = construct_url(environ)
-            args = urllib.urlencode({'service': service})
-            location = authority + "login?" + args
-            exce = CASAuthenticate(location)
-        return exce.wsgi_application(environ, start_response)
-    return cas_application
-
-middleware = AuthCASHandler
-
-__all__ = ['CASLoginFailure', 'CASAuthenticate', 'AuthCASHandler' ]
-
-if '__main__' == __name__:
-    authority = "https://secure.its.yale.edu/cas/servlet/"
-    from paste.wsgilib import dump_environ
-    from paste.httpserver import serve
-    from paste.httpexceptions import *
-    serve(HTTPExceptionHandler(
-             AuthCASHandler(dump_environ, authority)))
diff --git a/lib/paste/auth/cookie.py b/lib/paste/auth/cookie.py
@@ -1,395 +0,0 @@
-# (c) 2005 Clark C. Evans
-# This module is part of the Python Paste Project and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-# This code was written with funding by http://prometheusresearch.com
-"""
-Cookie "Saved" Authentication
-
-This authentication middleware saves the current REMOTE_USER,
-REMOTE_SESSION, and any other environment variables specified in a
-cookie so that it can be retrieved during the next request without
-requiring re-authentication. This uses a session cookie on the client
-side (so it goes away when the user closes their window) and does
-server-side expiration.
-
-Following is a very simple example where a form is presented asking for
-a user name (no actual checking), and dummy session identifier (perhaps
-corresponding to a database session id) is stored in the cookie.
-
-::
-
-  >>> from paste.httpserver import serve
-  >>> from paste.fileapp import DataApp
-  >>> from paste.httpexceptions import *
-  >>> from paste.auth.cookie import AuthCookieHandler
-  >>> from paste.wsgilib import parse_querystring
-  >>> def testapp(environ, start_response):
-  ...     user = dict(parse_querystring(environ)).get('user','')
-  ...     if user:
-  ...         environ['REMOTE_USER'] = user
-  ...         environ['REMOTE_SESSION'] = 'a-session-id'
-  ...     if environ.get('REMOTE_USER'):
-  ...         page = '<html><body>Welcome %s (%s)</body></html>'
-  ...         page %= (environ['REMOTE_USER'], environ['REMOTE_SESSION'])
-  ...     else:
-  ...         page = ('<html><body><form><input name="user" />'
-  ...                 '<input type="submit" /></form></body></html>')
-  ...     return DataApp(page, content_type="text/html")(
-  ...                    environ, start_response)
-  >>> serve(AuthCookieHandler(testapp))
-  serving on...
-
-"""
-
-import hmac, base64, random, time, warnings
-try:
-    from hashlib import sha1
-except ImportError:
-    # NOTE: We have to use the callable with hashlib (hashlib.sha1),
-    # otherwise hmac only accepts the sha module object itself
-    import sha as sha1
-from paste.request import get_cookies
-
-def make_time(value):
-    return time.strftime("%Y%m%d%H%M", time.gmtime(value))
-_signature_size = len(hmac.new('x', 'x', sha1).digest())
-_header_size = _signature_size + len(make_time(time.time()))
-
-# @@: Should this be using urllib.quote?
-# build encode/decode functions to safely pack away values
-_encode = [('\\', '\\x5c'), ('"', '\\x22'),
-           ('=', '\\x3d'), (';', '\\x3b')]
-_decode = [(v, k) for (k, v) in _encode]
-_decode.reverse()
-def encode(s, sublist = _encode):
-    return reduce((lambda a, (b, c): a.replace(b, c)), sublist, str(s))
-decode = lambda s: encode(s, _decode)
-
-class CookieTooLarge(RuntimeError):
-    def __init__(self, content, cookie):
-        RuntimeError.__init__("Signed cookie exceeds maximum size of 4096")
-        self.content = content
-        self.cookie = cookie
-
-_all_chars = ''.join([chr(x) for x in range(0, 255)])
-def new_secret():
-    """ returns a 64 byte secret """
-    return ''.join(random.sample(_all_chars, 64))
-
-class AuthCookieSigner(object):
-    """
-    save/restore ``environ`` entries via digially signed cookie
-
-    This class converts content into a timed and digitally signed
-    cookie, as well as having the facility to reverse this procedure.
-    If the cookie, after the content is encoded and signed exceeds the
-    maximum length (4096), then CookieTooLarge exception is raised.
-
-    The timeout of the cookie is handled on the server side for a few
-    reasons.  First, if a 'Expires' directive is added to a cookie, then
-    the cookie becomes persistent (lasting even after the browser window
-    has closed). Second, the user's clock may be wrong (perhaps
-    intentionally). The timeout is specified in minutes; and expiration
-    date returned is rounded to one second.
-
-    Constructor Arguments:
-
-        ``secret``
-
-            This is a secret key if you want to syncronize your keys so
-            that the cookie will be good across a cluster of computers.
-            It is recommended via the HMAC specification (RFC 2104) that
-            the secret key be 64 bytes since this is the block size of
-            the hashing.  If you do not provide a secret key, a random
-            one is generated each time you create the handler; this
-            should be sufficient for most cases.
-
-        ``timeout``
-
-            This is the time (in minutes) from which the cookie is set
-            to expire.  Note that on each request a new (replacement)
-            cookie is sent, hence this is effectively a session timeout
-            parameter for your entire cluster.  If you do not provide a
-            timeout, it is set at 30 minutes.
-
-        ``maxlen``
-
-            This is the maximum size of the *signed* cookie; hence the
-            actual content signed will be somewhat less.  If the cookie
-            goes over this size, a ``CookieTooLarge`` exception is
-            raised so that unexpected handling of cookies on the client
-            side are avoided.  By default this is set at 4k (4096 bytes),
-            which is the standard cookie size limit.
-
-    """
-    def __init__(self, secret = None, timeout = None, maxlen = None):
-        self.timeout = timeout or 30
-        if isinstance(timeout, basestring):
-            raise ValueError(
-                "Timeout must be a number (minutes), not a string (%r)"
-                % timeout)
-        self.maxlen  = maxlen or 4096
-        self.secret = secret or new_secret()
-
-    def sign(self, content):
-        """
-        Sign the content returning a valid cookie (that does not
-        need to be escaped and quoted).  The expiration of this
-        cookie is handled server-side in the auth() function.
-        """
-        cookie = base64.encodestring(
-            hmac.new(self.secret, content, sha1).digest() +
-            make_time(time.time() + 60*self.timeout) +
-            content)[:-1]
-        cookie = cookie.replace("/", "_").replace("=", "~")
-        if len(cookie) > self.maxlen:
-            raise CookieTooLarge(content, cookie)
-        return cookie
-
-    def auth(self, cookie):
-        """
-        Authenticate the cooke using the signature, verify that it
-        has not expired; and return the cookie's content
-        """
-        decode = base64.decodestring(
-            cookie.replace("_", "/").replace("~", "="))
-        signature = decode[:_signature_size]
-        expires = decode[_signature_size:_header_size]
-        content = decode[_header_size:]
-        if signature == hmac.new(self.secret, content, sha1).digest():
-            if int(expires) > int(make_time(time.time())):
-                return content
-            else:
-                # This is the normal case of an expired cookie; just
-                # don't bother doing anything here.
-                pass
-        else:
-            # This case can happen if the server is restarted with a
-            # different secret; or if the user's IP address changed
-            # due to a proxy.  However, it could also be a break-in
-            # attempt -- so should it be reported?
-            pass
-
-class AuthCookieEnviron(list):
-    """
-    a list of environment keys to be saved via cookie
-
-    An instance of this object, found at ``environ['paste.auth.cookie']``
-    lists the `environ` keys that were restored from or will be added
-    to the digially signed cookie.  This object can be accessed from an
-    `environ` variable by using this module's name.
-    """
-    def __init__(self, handler, scanlist):
-        list.__init__(self, scanlist)
-        self.handler = handler
-    def append(self, value):
-        if value in self:
-            return
-        list.append(self, str(value))
-
-class AuthCookieHandler(object):
-    """
-    the actual handler that should be put in your middleware stack
-
-    This middleware uses cookies to stash-away a previously authenticated
-    user (and perhaps other variables) so that re-authentication is not
-    needed.  This does not implement sessions; and therefore N servers
-    can be syncronized to accept the same saved authentication if they
-    all use the same cookie_name and secret.
-
-    By default, this handler scans the `environ` for the REMOTE_USER
-    and REMOTE_SESSION key; if found, it is stored. It can be
-    configured to scan other `environ` keys as well -- but be careful
-    not to exceed 2-3k (so that the encoded and signed cookie does not
-    exceed 4k). You can ask it to handle other environment variables
-    by doing:
-
-       ``environ['paste.auth.cookie'].append('your.environ.variable')``
-
-
-    Constructor Arguments:
-
-        ``application``
-
-            This is the wrapped application which will have access to
-            the ``environ['REMOTE_USER']`` restored by this middleware.
-
-        ``cookie_name``
-
-            The name of the cookie used to store this content, by default
-            it is ``PASTE_AUTH_COOKIE``.
-
-        ``scanlist``
-
-            This is the initial set of ``environ`` keys to
-            save/restore to the signed cookie.  By default is consists
-            only of ``REMOTE_USER`` and ``REMOTE_SESSION``; any tuple
-            or list of environment keys will work.  However, be
-            careful, as the total saved size is limited to around 3k.
-
-        ``signer``
-
-            This is the signer object used to create the actual cookie
-            values, by default, it is ``AuthCookieSigner`` and is passed
-            the remaining arguments to this function: ``secret``,
-            ``timeout``, and ``maxlen``.
-
-    At this time, each cookie is individually signed.  To store more
-    than the 4k of data; it is possible to sub-class this object to
-    provide different ``environ_name`` and ``cookie_name``
-    """
-    environ_name = 'paste.auth.cookie'
-    cookie_name  = 'PASTE_AUTH_COOKIE'
-    signer_class = AuthCookieSigner
-    environ_class = AuthCookieEnviron
-
-    def __init__(self, application, cookie_name=None, scanlist=None,
-                 signer=None, secret=None, timeout=None, maxlen=None):
-        if not signer:
-            signer = self.signer_class(secret, timeout, maxlen)
-        self.signer = signer
-        self.scanlist = scanlist or ('REMOTE_USER','REMOTE_SESSION')
-        self.application = application
-        self.cookie_name = cookie_name or self.cookie_name
-
-    def __call__(self, environ, start_response):
-        if self.environ_name in environ:
-            raise AssertionError("AuthCookie already installed!")
-        scanlist = self.environ_class(self, self.scanlist)
-        jar = get_cookies(environ)
-        if jar.has_key(self.cookie_name):
-            content = self.signer.auth(jar[self.cookie_name].value)
-            if content:
-                for pair in content.split(";"):
-                    (k, v) = pair.split("=")
-                    k = decode(k)
-                    if k not in scanlist:
-                        scanlist.append(k)
-                    if k in environ:
-                        continue
-                    environ[k] = decode(v)
-                    if 'REMOTE_USER' == k:
-                        environ['AUTH_TYPE'] = 'cookie'
-        environ[self.environ_name] = scanlist
-        if "paste.httpexceptions" in environ:
-            warnings.warn("Since paste.httpexceptions is hooked in your "
-                "processing chain before paste.auth.cookie, if an "
-                "HTTPRedirection is raised, the cookies this module sets "
-                "will not be included in your response.\n")
-
-        def response_hook(status, response_headers, exc_info=None):
-            """
-            Scan the environment for keys specified in the scanlist,
-            pack up their values, signs the content and issues a cookie.
-            """
-            scanlist = environ.get(self.environ_name)
-            assert scanlist and isinstance(scanlist, self.environ_class)
-            content = []
-            for k in scanlist:
-                v = environ.get(k)
-                if v is not None:
-                    if type(v) is not str:
-                        raise ValueError(
-                            "The value of the environmental variable %r "
-                            "is not a str (only str is allowed; got %r)"
-                            % (k, v))
-                    content.append("%s=%s" % (encode(k), encode(v)))
-            if content:
-                content = ";".join(content)
-                content = self.signer.sign(content)
-                cookie = '%s=%s; Path=/;' % (self.cookie_name, content)
-                if 'https' == environ['wsgi.url_scheme']:
-                    cookie += ' secure;'
-                response_headers.append(('Set-Cookie', cookie))
-            return start_response(status, response_headers, exc_info)
-        return self.application(environ, response_hook)
-
-middleware = AuthCookieHandler
-
-# Paste Deploy entry point:
-def make_auth_cookie(
-    app, global_conf,
-    # Should this get picked up from global_conf somehow?:
-    cookie_name='PASTE_AUTH_COOKIE',
-    scanlist=('REMOTE_USER', 'REMOTE_SESSION'),
-    # signer cannot be set
-    secret=None,
-    timeout=30,
-    maxlen=4096):
-    """
-    This middleware uses cookies to stash-away a previously
-    authenticated user (and perhaps other variables) so that
-    re-authentication is not needed.  This does not implement
-    sessions; and therefore N servers can be syncronized to accept the
-    same saved authentication if they all use the same cookie_name and
-    secret.
-
-    By default, this handler scans the `environ` for the REMOTE_USER
-    and REMOTE_SESSION key; if found, it is stored. It can be
-    configured to scan other `environ` keys as well -- but be careful
-    not to exceed 2-3k (so that the encoded and signed cookie does not
-    exceed 4k). You can ask it to handle other environment variables
-    by doing:
-
-       ``environ['paste.auth.cookie'].append('your.environ.variable')``
-
-    Configuration:
-
-        ``cookie_name``
-
-            The name of the cookie used to store this content, by
-            default it is ``PASTE_AUTH_COOKIE``.
-
-        ``scanlist``
-
-            This is the initial set of ``environ`` keys to
-            save/restore to the signed cookie.  By default is consists
-            only of ``REMOTE_USER`` and ``REMOTE_SESSION``; any
-            space-separated list of environment keys will work.
-            However, be careful, as the total saved size is limited to
-            around 3k.
-
-        ``secret``
-
-            The secret that will be used to sign the cookies.  If you
-            don't provide one (and none is set globally) then a random
-            secret will be created.  Each time the server is restarted
-            a new secret will then be created and all cookies will
-            become invalid!  This can be any string value.
-
-        ``timeout``
-
-            The time to keep the cookie, expressed in minutes.  This
-            is handled server-side, so a new cookie with a new timeout
-            is added to every response.
-
-        ``maxlen``
-
-            The maximum length of the cookie that is sent (default 4k,
-            which is a typical browser maximum)
-        
-    """
-    if isinstance(scanlist, basestring):
-        scanlist = scanlist.split()
-    if secret is None and global_conf.get('secret'):
-        secret = global_conf['secret']
-    try:
-        timeout = int(timeout)
-    except ValueError:
-        raise ValueError('Bad value for timeout (must be int): %r'
-                         % timeout)
-    try:
-        maxlen = int(maxlen)
-    except ValueError:
-        raise ValueError('Bad value for maxlen (must be int): %r'
-                         % maxlen)
-    return AuthCookieHandler(
-        app, cookie_name=cookie_name, scanlist=scanlist,
-        secret=secret, timeout=timeout, maxlen=maxlen)
-
-__all__ = ['AuthCookieHandler', 'AuthCookieSigner', 'AuthCookieEnviron']
-
-if "__main__" == __name__:
-    import doctest
-    doctest.testmod(optionflags=doctest.ELLIPSIS)
-
diff --git a/lib/paste/auth/digest.py b/lib/paste/auth/digest.py
@@ -1,213 +0,0 @@
-# (c) 2005 Clark C. Evans
-# This module is part of the Python Paste Project and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-# This code was written with funding by http://prometheusresearch.com
-"""
-Digest HTTP/1.1 Authentication
-
-This module implements ``Digest`` authentication as described by
-RFC 2617 [1]_ .
-
-Basically, you just put this module before your application, and it
-takes care of requesting and handling authentication requests.  This
-module has been tested with several common browsers "out-in-the-wild".
-
->>> from paste.wsgilib import dump_environ
->>> from paste.httpserver import serve
->>> # from paste.auth.digest import digest_password, AuthDigestHandler
->>> realm = 'Test Realm'
->>> def authfunc(environ, realm, username):
-...     return digest_password(realm, username, username)
->>> serve(AuthDigestHandler(dump_environ, realm, authfunc))
-serving on...
-
-This code has not been audited by a security expert, please use with
-caution (or better yet, report security holes). At this time, this
-implementation does not provide for further challenges, nor does it
-support Authentication-Info header.  It also uses md5, and an option
-to use sha would be a good thing.
-
-.. [1] http://www.faqs.org/rfcs/rfc2617.html
-"""
-from paste.httpexceptions import HTTPUnauthorized
-from paste.httpheaders import *
-try:
-    from hashlib import md5
-except ImportError:
-    from md5 import md5
-import time, random
-
-def digest_password(realm, username, password):
-    """ construct the appropriate hashcode needed for HTTP digest """
-    return md5("%s:%s:%s" % (username, realm, password)).hexdigest()
-
-class AuthDigestAuthenticator(object):
-    """ implementation of RFC 2617 - HTTP Digest Authentication """
-    def __init__(self, realm, authfunc):
-        self.nonce    = {} # list to prevent replay attacks
-        self.authfunc = authfunc
-        self.realm    = realm
-
-    def build_authentication(self, stale = ''):
-        """ builds the authentication error """
-        nonce  = md5(
-            "%s:%s" % (time.time(), random.random())).hexdigest()
-        opaque = md5(
-            "%s:%s" % (time.time(), random.random())).hexdigest()
-        self.nonce[nonce] = None
-        parts = {'realm': self.realm, 'qop': 'auth',
-                 'nonce': nonce, 'opaque': opaque }
-        if stale:
-            parts['stale'] = 'true'
-        head = ", ".join(['%s="%s"' % (k, v) for (k, v) in parts.items()])
-        head = [("WWW-Authenticate", 'Digest %s' % head)]
-        return HTTPUnauthorized(headers=head)
-
-    def compute(self, ha1, username, response, method,
-                      path, nonce, nc, cnonce, qop):
-        """ computes the authentication, raises error if unsuccessful """
-        if not ha1:
-            return self.build_authentication()
-        ha2 = md5('%s:%s' % (method, path)).hexdigest()
-        if qop:
-            chk = "%s:%s:%s:%s:%s:%s" % (ha1, nonce, nc, cnonce, qop, ha2)
-        else:
-            chk = "%s:%s:%s" % (ha1, nonce, ha2)
-        if response != md5(chk).hexdigest():
-            if nonce in self.nonce:
-                del self.nonce[nonce]
-            return self.build_authentication()
-        pnc = self.nonce.get(nonce,'00000000')
-        if nc <= pnc:
-            if nonce in self.nonce:
-                del self.nonce[nonce]
-            return self.build_authentication(stale = True)
-        self.nonce[nonce] = nc
-        return username
-
-    def authenticate(self, environ):
-        """ This function takes a WSGI environment and authenticates
-            the request returning authenticated user or error.
-        """
-        method = REQUEST_METHOD(environ)
-        fullpath = SCRIPT_NAME(environ) + PATH_INFO(environ)
-        authorization = AUTHORIZATION(environ)
-        if not authorization:
-            return self.build_authentication()
-        (authmeth, auth) = authorization.split(" ", 1)
-        if 'digest' != authmeth.lower():
-            return self.build_authentication()
-        amap = {}
-        for itm in auth.split(", "):
-            (k,v) = [s.strip() for s in itm.split("=", 1)]
-            amap[k] = v.replace('"', '')
-        try:
-            username = amap['username']
-            authpath = amap['uri']
-            nonce    = amap['nonce']
-            realm    = amap['realm']
-            response = amap['response']
-            assert authpath.split("?", 1)[0] in fullpath
-            assert realm == self.realm
-            qop      = amap.get('qop', '')
-            cnonce   = amap.get('cnonce', '')
-            nc       = amap.get('nc', '00000000')
-            if qop:
-                assert 'auth' == qop
-                assert nonce and nc
-        except:
-            return self.build_authentication()
-        ha1 = self.authfunc(environ, realm, username)
-        return self.compute(ha1, username, response, method, authpath,
-                            nonce, nc, cnonce, qop)
-
-    __call__ = authenticate
-
-class AuthDigestHandler(object):
-    """
-    middleware for HTTP Digest authentication (RFC 2617)
-
-    This component follows the procedure below:
-
-        0. If the REMOTE_USER environment variable is already populated;
-           then this middleware is a no-op, and the request is passed
-           along to the application.
-
-        1. If the HTTP_AUTHORIZATION header was not provided or specifies
-           an algorithem other than ``digest``, then a HTTPUnauthorized
-           response is generated with the challenge.
-
-        2. If the response is malformed or or if the user's credientials
-           do not pass muster, another HTTPUnauthorized is raised.
-
-        3. If all goes well, and the user's credintials pass; then
-           REMOTE_USER environment variable is filled in and the
-           AUTH_TYPE is listed as 'digest'.
-
-    Parameters:
-
-        ``application``
-
-            The application object is called only upon successful
-            authentication, and can assume ``environ['REMOTE_USER']``
-            is set.  If the ``REMOTE_USER`` is already set, this
-            middleware is simply pass-through.
-
-        ``realm``
-
-            This is a identifier for the authority that is requesting
-            authorization.  It is shown to the user and should be unique
-            within the domain it is being used.
-
-        ``authfunc``
-
-            This is a callback function which performs the actual
-            authentication; the signature of this callback is:
-
-              authfunc(environ, realm, username) -> hashcode
-
-            This module provides a 'digest_password' helper function
-            which can help construct the hashcode; it is recommended
-            that the hashcode is stored in a database, not the user's
-            actual password (since you only need the hashcode).
-    """
-    def __init__(self, application, realm, authfunc):
-        self.authenticate = AuthDigestAuthenticator(realm, authfunc)
-        self.application = application
-
-    def __call__(self, environ, start_response):
-        username = REMOTE_USER(environ)
-        if not username:
-            result = self.authenticate(environ)
-            if isinstance(result, str):
-                AUTH_TYPE.update(environ,'digest')
-                REMOTE_USER.update(environ, result)
-            else:
-                return result.wsgi_application(environ, start_response)
-        return self.application(environ, start_response)
-
-middleware = AuthDigestHandler
-
-__all__ = ['digest_password', 'AuthDigestHandler' ]
-
-def make_digest(app, global_conf, realm, authfunc, **kw):
-    """
-    Grant access via digest authentication
-
-    Config looks like this::
-
-      [filter:grant]
-      use = egg:Paste#auth_digest
-      realm=myrealm
-      authfunc=somepackage.somemodule:somefunction
-      
-    """
-    from paste.util.import_string import eval_import
-    import types
-    authfunc = eval_import(authfunc)
-    assert isinstance(authfunc, types.FunctionType), "authfunc must resolve to a function"
-    return AuthDigestHandler(app, realm, authfunc)
-
-if "__main__" == __name__:
-    import doctest
-    doctest.testmod(optionflags=doctest.ELLIPSIS)
diff --git a/lib/paste/auth/form.py b/lib/paste/auth/form.py
@@ -1,149 +0,0 @@
-# (c) 2005 Clark C. Evans
-# This module is part of the Python Paste Project and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-# This code was written with funding by http://prometheusresearch.com
-"""
-Authentication via HTML Form
-
-This is a very simple HTML form login screen that asks for the username
-and password.  This middleware component requires that an authorization
-function taking the name and passsword and that it be placed in your
-application stack. This class does not include any session management
-code or way to save the user's authorization; however, it is easy enough
-to put ``paste.auth.cookie`` in your application stack.
-
->>> from paste.wsgilib import dump_environ
->>> from paste.httpserver import serve
->>> from paste.auth.cookie import AuthCookieHandler
->>> from paste.auth.form import AuthFormHandler
->>> def authfunc(environ, username, password):
-...    return username == password
->>> serve(AuthCookieHandler(
-...           AuthFormHandler(dump_environ, authfunc)))
-serving on...
-
-"""
-from paste.request import construct_url, parse_formvars
-
-TEMPLATE = """\
-<html>
-  <head><title>Please Login!</title></head>
-  <body>
-    <h1>Please Login</h1>
-    <form action="%s" method="post">
-      <dl>
-        <dt>Username:</dt>
-        <dd><input type="text" name="username"></dd>
-        <dt>Password:</dt>
-        <dd><input type="password" name="password"></dd>
-      </dl>
-      <input type="submit" name="authform" />
-      <hr />
-    </form>
-  </body>
-</html>
-"""
-
-class AuthFormHandler(object):
-    """
-    HTML-based login middleware
-
-    This causes a HTML form to be returned if ``REMOTE_USER`` is
-    not found in the ``environ``.  If the form is returned, the
-    ``username`` and ``password`` combination are given to a
-    user-supplied authentication function, ``authfunc``.  If this
-    is successful, then application processing continues.
-
-    Parameters:
-
-        ``application``
-
-            The application object is called only upon successful
-            authentication, and can assume ``environ['REMOTE_USER']``
-            is set.  If the ``REMOTE_USER`` is already set, this
-            middleware is simply pass-through.
-
-        ``authfunc``
-
-            This is a mandatory user-defined function which takes a
-            ``environ``, ``username`` and ``password`` for its first
-            three arguments.  It should return ``True`` if the user is
-            authenticated.
-
-        ``template``
-
-            This is an optional (a default is provided) HTML
-            fragment that takes exactly one ``%s`` substution
-            argument; which *must* be used for the form's ``action``
-            to ensure that this middleware component does not alter
-            the current path.  The HTML form must use ``POST`` and
-            have two input names:  ``username`` and ``password``.
-
-    Since the authentication form is submitted (via ``POST``)
-    neither the ``PATH_INFO`` nor the ``QUERY_STRING`` are accessed,
-    and hence the current path remains _unaltered_ through the
-    entire authentication process. If authentication succeeds, the
-    ``REQUEST_METHOD`` is converted from a ``POST`` to a ``GET``,
-    so that a redirect is unnecessary (unlike most form auth
-    implementations)
-    """
-
-    def __init__(self, application, authfunc, template=None):
-        self.application = application
-        self.authfunc = authfunc
-        self.template = template or TEMPLATE
-
-    def __call__(self, environ, start_response):
-        username = environ.get('REMOTE_USER','')
-        if username:
-            return self.application(environ, start_response)
-
-        if 'POST' == environ['REQUEST_METHOD']:
-            formvars = parse_formvars(environ, include_get_vars=False)
-            username = formvars.get('username')
-            password = formvars.get('password')
-            if username and password:
-                if self.authfunc(environ, username, password):
-                    environ['AUTH_TYPE'] = 'form'
-                    environ['REMOTE_USER'] = username
-                    environ['REQUEST_METHOD'] = 'GET'
-                    environ['CONTENT_LENGTH'] = ''
-                    environ['CONTENT_TYPE'] = ''
-                    del environ['paste.parsed_formvars']
-                    return self.application(environ, start_response)
-
-        content = self.template % construct_url(environ)
-        start_response("200 OK", [('Content-Type', 'text/html'),
-                                  ('Content-Length', str(len(content)))])
-        return [content]
-
-middleware = AuthFormHandler
-
-__all__ = ['AuthFormHandler']
-
-def make_form(app, global_conf, realm, authfunc, **kw):
-    """
-    Grant access via form authentication
-
-    Config looks like this::
-
-      [filter:grant]
-      use = egg:Paste#auth_form
-      realm=myrealm
-      authfunc=somepackage.somemodule:somefunction
-      
-    """
-    from paste.util.import_string import eval_import
-    import types
-    authfunc = eval_import(authfunc)
-    assert isinstance(authfunc, types.FunctionType), "authfunc must resolve to a function"
-    template = kw.get('template')
-    if template is not None:
-        template = eval_import(template)
-        assert isinstance(template, str), "template must resolve to a string"
-
-    return AuthFormHandler(app, authfunc, template)
-
-if "__main__" == __name__:
-    import doctest
-    doctest.testmod(optionflags=doctest.ELLIPSIS)
diff --git a/lib/paste/auth/grantip.py b/lib/paste/auth/grantip.py
@@ -1,113 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-Grant roles and logins based on IP address.
-"""
-from paste.util import ip4
-
-class GrantIPMiddleware(object):
-
-    """
-    On each request, ``ip_map`` is checked against ``REMOTE_ADDR``
-    and logins and roles are assigned based on that.
-
-    ``ip_map`` is a map of {ip_mask: (username, roles)}.  Either
-    ``username`` or ``roles`` may be None.  Roles may also be prefixed
-    with ``-``, like ``'-system'`` meaning that role should be
-    revoked.  ``'__remove__'`` for a username will remove the username.
-
-    If ``clobber_username`` is true (default) then any user
-    specification will override the current value of ``REMOTE_USER``.
-    ``'__remove__'`` will always clobber the username.
-
-    ``ip_mask`` is something that `paste.util.ip4:IP4Range
-    <class-paste.util.ip4.IP4Range.html>`_ can parse.  Simple IP
-    addresses, IP/mask, ip<->ip ranges, and hostnames are allowed.
-    """
-
-    def __init__(self, app, ip_map, clobber_username=True):
-        self.app = app
-        self.ip_map = []
-        for key, value in ip_map.items():
-            self.ip_map.append((ip4.IP4Range(key),
-                                self._convert_user_role(value[0], value[1])))
-        self.clobber_username = clobber_username
-
-    def _convert_user_role(self, username, roles):
-        if roles and isinstance(roles, basestring):
-            roles = roles.split(',')
-        return (username, roles)
-        
-    def __call__(self, environ, start_response):
-        addr = ip4.ip2int(environ['REMOTE_ADDR'], False)
-        remove_user = False
-        add_roles = []
-        for range, (username, roles) in self.ip_map:
-            if addr in range:
-                if roles:
-                    add_roles.extend(roles)
-                if username == '__remove__':
-                    remove_user = True
-                elif username:
-                    if (not environ.get('REMOTE_USER')
-                        or self.clobber_username):
-                        environ['REMOTE_USER'] = username
-        if (remove_user and 'REMOTE_USER' in environ):
-            del environ['REMOTE_USER']
-        if roles:
-            self._set_roles(environ, add_roles)
-        return self.app(environ, start_response)
-
-    def _set_roles(self, environ, roles):
-        cur_roles = environ.get('REMOTE_USER_TOKENS', '').split(',')
-        # Get rid of empty roles:
-        cur_roles = filter(None, cur_roles)
-        remove_roles = []
-        for role in roles:
-            if role.startswith('-'):
-                remove_roles.append(role[1:])
-            else:
-                if role not in cur_roles:
-                    cur_roles.append(role)
-        for role in remove_roles:
-            if role in cur_roles:
-                cur_roles.remove(role)
-        environ['REMOTE_USER_TOKENS'] = ','.join(cur_roles)
-        
-                
-def make_grantip(app, global_conf, clobber_username=False, **kw):
-    """
-    Grant roles or usernames based on IP addresses.
-
-    Config looks like this::
-
-      [filter:grant]
-      use = egg:Paste#grantip
-      clobber_username = true
-      # Give localhost system role (no username):
-      127.0.0.1 = -:system
-      # Give everyone in 192.168.0.* editor role:
-      192.168.0.0/24 = -:editor
-      # Give one IP the username joe:
-      192.168.0.7 = joe
-      # And one IP is should not be logged in:
-      192.168.0.10 = __remove__:-editor
-      
-    """
-    from paste.deploy.converters import asbool
-    clobber_username = asbool(clobber_username)
-    ip_map = {}
-    for key, value in kw.items():
-        if ':' in value:
-            username, role = value.split(':', 1)
-        else:
-            username = value
-            role = ''
-        if username == '-':
-            username = ''
-        if role == '-':
-            role = ''
-        ip_map[key] = value
-    return GrantIPMiddleware(app, ip_map, clobber_username)
-    
-    
diff --git a/lib/paste/auth/multi.py b/lib/paste/auth/multi.py
@@ -1,79 +0,0 @@
-# (c) 2005 Clark C. Evans
-# This module is part of the Python Paste Project and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-# This code was written with funding by http://prometheusresearch.com
-"""
-Authentication via Multiple Methods
-
-In some environments, the choice of authentication method to be used
-depends upon the environment and is not "fixed".  This middleware allows
-N authentication methods to be registered along with a goodness function
-which determines which method should be used. The following example
-demonstrates how to use both form and digest authentication in a server
-stack; by default it uses form-based authentication unless
-``*authmeth=digest`` is specified as a query argument.
-
->>> from paste.auth import form, cookie, digest, multi
->>> from paste.wsgilib import dump_environ
->>> from paste.httpserver import serve
->>>
->>> multi = multi.MultiHandler(dump_environ)
->>> def authfunc(environ, realm, user):
-...     return digest.digest_password(realm, user, user)
->>> multi.add_method('digest', digest.middleware, "Test Realm", authfunc)
->>> multi.set_query_argument('digest')
->>>
->>> def authfunc(environ, username, password):
-...     return username == password
->>> multi.add_method('form', form.middleware, authfunc)
->>> multi.set_default('form')
->>> serve(cookie.middleware(multi))
-serving on...
-
-"""
-
-class MultiHandler(object):
-    """
-    Multiple Authentication Handler
-
-    This middleware provides two othogonal facilities:
-
-      - a manner to register any number of authentication middlewares
-
-      - a mechanism to register predicates which cause one of the
-        registered middlewares to be used depending upon the request
-
-    If none of the predicates returns True, then the application is
-    invoked directly without middleware
-    """
-    def __init__(self, application):
-        self.application = application
-        self.default = application
-        self.binding = {}
-        self.predicate = []
-    def add_method(self, name, factory, *args, **kwargs):
-        self.binding[name] = factory(self.application, *args, **kwargs)
-    def add_predicate(self, name, checker):
-        self.predicate.append((checker, self.binding[name]))
-    def set_default(self, name):
-        """ set default authentication method """
-        self.default = self.binding[name]
-    def set_query_argument(self, name, key = '*authmeth', value = None):
-        """ choose authentication method based on a query argument """
-        lookfor = "%s=%s" % (key, value or name)
-        self.add_predicate(name,
-            lambda environ: lookfor in environ.get('QUERY_STRING',''))
-    def __call__(self, environ, start_response):
-        for (checker, binding) in self.predicate:
-            if checker(environ):
-                return binding(environ, start_response)
-        return self.default(environ, start_response)
-
-middleware = MultiHandler
-
-__all__ = ['MultiHandler']
-
-if "__main__" == __name__:
-    import doctest
-    doctest.testmod(optionflags=doctest.ELLIPSIS)
-
diff --git a/lib/paste/auth/open_id.py b/lib/paste/auth/open_id.py
@@ -1,412 +0,0 @@
-# (c) 2005 Ben Bangert
-# This module is part of the Python Paste Project and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-"""
-OpenID Authentication (Consumer)
-
-OpenID is a distributed authentication system for single sign-on originally
-developed at/for LiveJournal.com.
-
-    http://openid.net/
-
-URL. You can have multiple identities in the same way you can have multiple
-URLs. All OpenID does is provide a way to prove that you own a URL (identity).
-And it does this without passing around your password, your email address, or
-anything you don't want it to. There's no profile exchange component at all:
-your profiile is your identity URL, but recipients of your identity can then
-learn more about you from any public, semantically interesting documents
-linked thereunder (FOAF, RSS, Atom, vCARD, etc.).
-
-``Note``: paste.auth.openid requires installation of the Python-OpenID
-libraries::
-
-    http://www.openidenabled.com/
-
-This module is based highly off the consumer.py that Python OpenID comes with.
-
-Using the OpenID Middleware
-===========================
-
-Using the OpenID middleware is fairly easy, the most minimal example using the
-basic login form thats included::
-
-    # Add to your wsgi app creation
-    from paste.auth import open_id
-
-    wsgi_app = open_id.middleware(wsgi_app, '/somewhere/to/store/openid/data')
-
-You will now have the OpenID form available at /oid on your site. Logging in will
-verify that the login worked.
-
-A more complete login should involve having the OpenID middleware load your own
-login page after verifying the OpenID URL so that you can retain the login
-information in your webapp (session, cookies, etc.)::
-
-    wsgi_app = open_id.middleware(wsgi_app, '/somewhere/to/store/openid/data',
-                                  login_redirect='/your/login/code')
-
-Your login code should then be configured to retrieve 'paste.auth.open_id' for
-the users OpenID URL. If this key does not exist, the user has not logged in.
-
-Once the login is retrieved, it should be saved in your webapp, and the user
-should be redirected to wherever they would normally go after a successful
-login.
-"""
-
-__all__ = ['AuthOpenIDHandler']
-
-import cgi
-import urlparse
-import re
-
-import paste.request
-from paste import httpexceptions
-
-def quoteattr(s):
-    qs = cgi.escape(s, 1)
-    return '"%s"' % (qs,)
-
-# You may need to manually add the openid package into your
-# python path if you don't have it installed with your system python.
-# If so, uncomment the line below, and change the path where you have
-# Python-OpenID.
-# sys.path.append('/path/to/openid/')
-
-from openid.store import filestore
-from openid.consumer import consumer
-from openid.oidutil import appendArgs
-
-class AuthOpenIDHandler(object):
-    """
-    This middleware implements OpenID Consumer behavior to authenticate a
-    URL against an OpenID Server.
-    """
-
-    def __init__(self, app, data_store_path, auth_prefix='/oid',
-                 login_redirect=None, catch_401=False,
-                 url_to_username=None):
-        """
-        Initialize the OpenID middleware
-
-        ``app``
-            Your WSGI app to call
-            
-        ``data_store_path``
-            Directory to store crypto data in for use with OpenID servers.
-            
-        ``auth_prefix``
-            Location for authentication process/verification
-            
-        ``login_redirect``
-            Location to load after successful process of login
-            
-        ``catch_401``
-            If true, then any 401 responses will turn into open ID login
-            requirements.
-            
-        ``url_to_username``
-            A function called like ``url_to_username(environ, url)``, which should
-            return a string username.  If not given, the URL will be the username.
-        """
-        store = filestore.FileOpenIDStore(data_store_path)
-        self.oidconsumer = consumer.OpenIDConsumer(store)
-
-        self.app = app
-        self.auth_prefix = auth_prefix
-        self.data_store_path = data_store_path
-        self.login_redirect = login_redirect
-        self.catch_401 = catch_401
-        self.url_to_username = url_to_username
-
-    def __call__(self, environ, start_response):
-        if environ['PATH_INFO'].startswith(self.auth_prefix):
-            # Let's load everything into a request dict to pass around easier
-            request = dict(environ=environ, start=start_response, body=[])
-            request['base_url'] = paste.request.construct_url(environ, with_path_info=False,
-                                                              with_query_string=False)
-
-            path = re.sub(self.auth_prefix, '', environ['PATH_INFO'])
-            request['parsed_uri'] = urlparse.urlparse(path)
-            request['query'] = dict(paste.request.parse_querystring(environ))
-
-            path = request['parsed_uri'][2]
-            if path == '/' or not path:
-                return self.render(request)
-            elif path == '/verify':
-                return self.do_verify(request)
-            elif path == '/process':
-                return self.do_process(request)
-            else:
-                return self.not_found(request)
-        else:
-            if self.catch_401:
-                return self.catch_401_app_call(environ, start_response)
-            return self.app(environ, start_response)
-
-    def catch_401_app_call(self, environ, start_response):
-        """
-        Call the application, and redirect if the app returns a 401 response
-        """
-        was_401 = []
-        def replacement_start_response(status, headers, exc_info=None):
-            if int(status.split(None, 1)) == 401:
-                # @@: Do I need to append something to go back to where we
-                # came from?
-                was_401.append(1)
-                def dummy_writer(v):
-                    pass
-                return dummy_writer
-            else:
-                return start_response(status, headers, exc_info)
-        app_iter = self.app(environ, replacement_start_response)
-        if was_401:
-            try:
-                list(app_iter)
-            finally:
-                if hasattr(app_iter, 'close'):
-                    app_iter.close()
-            redir_url = paste.request.construct_url(environ, with_path_info=False,
-                                                    with_query_string=False)
-            exc = httpexceptions.HTTPTemporaryRedirect(redir_url)
-            return exc.wsgi_application(environ, start_response)
-        else:
-            return app_iter
-
-    def do_verify(self, request):
-        """Process the form submission, initating OpenID verification.
-        """
-
-        # First, make sure that the user entered something
-        openid_url = request['query'].get('openid_url')
-        if not openid_url:
-            return self.render(request, 'Enter an identity URL to verify.',
-                        css_class='error', form_contents=openid_url)
-
-        oidconsumer = self.oidconsumer
-
-        # Then, ask the library to begin the authorization.
-        # Here we find out the identity server that will verify the
-        # user's identity, and get a token that allows us to
-        # communicate securely with the identity server.
-        status, info = oidconsumer.beginAuth(openid_url)
-
-        # If the URL was unusable (either because of network
-        # conditions, a server error, or that the response returned
-        # was not an OpenID identity page), the library will return
-        # an error code. Let the user know that that URL is unusable.
-        if status in [consumer.HTTP_FAILURE, consumer.PARSE_ERROR]:
-            if status == consumer.HTTP_FAILURE:
-                fmt = 'Failed to retrieve <q>%s</q>'
-            else:
-                fmt = 'Could not find OpenID information in <q>%s</q>'
-
-            message = fmt % (cgi.escape(openid_url),)
-            return self.render(request, message, css_class='error', form_contents=openid_url)
-        elif status == consumer.SUCCESS:
-            # The URL was a valid identity URL. Now we construct a URL
-            # that will get us to process the server response. We will
-            # need the token from the beginAuth call when processing
-            # the response. A cookie or a session object could be used
-            # to accomplish this, but for simplicity here we just add
-            # it as a query parameter of the return-to URL.
-            return_to = self.build_url(request, 'process', token=info.token)
-
-            # Now ask the library for the URL to redirect the user to
-            # his OpenID server. It is required for security that the
-            # return_to URL must be under the specified trust_root. We
-            # just use the base_url for this server as a trust root.
-            redirect_url = oidconsumer.constructRedirect(
-                info, return_to, trust_root=request['base_url'])
-
-            # Send the redirect response
-            return self.redirect(request, redirect_url)
-        else:
-            assert False, 'Not reached'
-
-    def do_process(self, request):
-        """Handle the redirect from the OpenID server.
-        """
-        oidconsumer = self.oidconsumer
-
-        # retrieve the token from the environment (in this case, the URL)
-        token = request['query'].get('token', '')
-
-        # Ask the library to check the response that the server sent
-        # us.  Status is a code indicating the response type. info is
-        # either None or a string containing more information about
-        # the return type.
-        status, info = oidconsumer.completeAuth(token, request['query'])
-
-        css_class = 'error'
-        openid_url = None
-        if status == consumer.FAILURE and info:
-            # In the case of failure, if info is non-None, it is the
-            # URL that we were verifying. We include it in the error
-            # message to help the user figure out what happened.
-            openid_url = info
-            fmt = "Verification of %s failed."
-            message = fmt % (cgi.escape(openid_url),)
-        elif status == consumer.SUCCESS:
-            # Success means that the transaction completed without
-            # error. If info is None, it means that the user cancelled
-            # the verification.
-            css_class = 'alert'
-            if info:
-                # This is a successful verification attempt. If this
-                # was a real application, we would do our login,
-                # comment posting, etc. here.
-                openid_url = info
-                if self.url_to_username:
-                    username = self.url_to_username(request['environ'], openid_url)
-                else:
-                    username = openid_url
-                if 'paste.auth_tkt.set_user' in request['environ']:
-                    request['environ']['paste.auth_tkt.set_user'](username)
-                if not self.login_redirect:
-                    fmt = ("If you had supplied a login redirect path, you would have "
-                           "been redirected there.  "
-                           "You have successfully verified %s as your identity.")
-                    message = fmt % (cgi.escape(openid_url),)
-                else:
-                    # @@: This stuff doesn't make sense to me; why not a remote redirect?
-                    request['environ']['paste.auth.open_id'] = openid_url
-                    request['environ']['PATH_INFO'] = self.login_redirect
-                    return self.app(request['environ'], request['start'])
-                    #exc = httpexceptions.HTTPTemporaryRedirect(self.login_redirect)
-                    #return exc.wsgi_application(request['environ'], request['start'])
-            else:
-                # cancelled
-                message = 'Verification cancelled'
-        else:
-            # Either we don't understand the code or there is no
-            # openid_url included with the error. Give a generic
-            # failure message. The library should supply debug
-            # information in a log.
-            message = 'Verification failed.'
-
-        return self.render(request, message, css_class, openid_url)
-
-    def build_url(self, request, action, **query):
-        """Build a URL relative to the server base_url, with the given
-        query parameters added."""
-        base = urlparse.urljoin(request['base_url'], self.auth_prefix + '/' + action)
-        return appendArgs(base, query)
-
-    def redirect(self, request, redirect_url):
-        """Send a redirect response to the given URL to the browser."""
-        response_headers = [('Content-type', 'text/plain'),
-                            ('Location', redirect_url)]
-        request['start']('302 REDIRECT', response_headers)
-        return ["Redirecting to %s" % redirect_url]
-
-    def not_found(self, request):
-        """Render a page with a 404 return code and a message."""
-        fmt = 'The path <q>%s</q> was not understood by this server.'
-        msg = fmt % (request['parsed_uri'],)
-        openid_url = request['query'].get('openid_url')
-        return self.render(request, msg, 'error', openid_url, status='404 Not Found')
-
-    def render(self, request, message=None, css_class='alert', form_contents=None,
-               status='200 OK', title="Python OpenID Consumer"):
-        """Render a page."""
-        response_headers = [('Content-type', 'text/html')]
-        request['start'](str(status), response_headers)
-
-        self.page_header(request, title)
-        if message:
-            request['body'].append("<div class='%s'>" % (css_class,))
-            request['body'].append(message)
-            request['body'].append("</div>")
-        self.page_footer(request, form_contents)
-        return request['body']
-
-    def page_header(self, request, title):
-        """Render the page header"""
-        request['body'].append('''\
-<html>
-  <head><title>%s</title></head>
-  <style type="text/css">
-      * {
-        font-family: verdana,sans-serif;
-      }
-      body {
-        width: 50em;
-        margin: 1em;
-      }
-      div {
-        padding: .5em;
-      }
-      table {
-        margin: none;
-        padding: none;
-      }
-      .alert {
-        border: 1px solid #e7dc2b;
-        background: #fff888;
-      }
-      .error {
-        border: 1px solid #ff0000;
-        background: #ffaaaa;
-      }
-      #verify-form {
-        border: 1px solid #777777;
-        background: #dddddd;
-        margin-top: 1em;
-        padding-bottom: 0em;
-      }
-  </style>
-  <body>
-    <h1>%s</h1>
-    <p>
-      This example consumer uses the <a
-      href="http://openid.schtuff.com/">Python OpenID</a> library. It
-      just verifies that the URL that you enter is your identity URL.
-    </p>
-''' % (title, title))
-
-    def page_footer(self, request, form_contents):
-        """Render the page footer"""
-        if not form_contents:
-            form_contents = ''
-
-        request['body'].append('''\
-    <div id="verify-form">
-      <form method="get" action=%s>
-        Identity&nbsp;URL:
-        <input type="text" name="openid_url" value=%s />
-        <input type="submit" value="Verify" />
-      </form>
-    </div>
-  </body>
-</html>
-''' % (quoteattr(self.build_url(request, 'verify')), quoteattr(form_contents)))
-
-
-middleware = AuthOpenIDHandler
-
-def make_open_id_middleware(
-    app,
-    global_conf,
-    # Should this default to something, or inherit something from global_conf?:
-    data_store_path,
-    auth_prefix='/oid',
-    login_redirect=None,
-    catch_401=False,
-    url_to_username=None,
-    apply_auth_tkt=False,
-    auth_tkt_logout_path=None):
-    from paste.deploy.converters import asbool
-    from paste.util import import_string
-    catch_401 = asbool(catch_401)
-    if url_to_username and isinstance(url_to_username, basestring):
-        url_to_username = import_string.eval_import(url_to_username)
-    apply_auth_tkt = asbool(apply_auth_tkt)
-    new_app = AuthOpenIDHandler(
-        app, data_store_path=data_store_path, auth_prefix=auth_prefix,
-        login_redirect=login_redirect, catch_401=catch_401,
-        url_to_username=url_to_username or None)
-    if apply_auth_tkt:
-        from paste.auth import auth_tkt
-        new_app = auth_tkt.make_auth_tkt_middleware(
-            new_app, global_conf, logout_path=auth_tkt_logout_path)
-    return new_app
diff --git a/lib/paste/cascade.py b/lib/paste/cascade.py
@@ -1,133 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-"""
-Cascades through several applications, so long as applications
-return ``404 Not Found``.
-"""
-from paste import httpexceptions
-from paste.util import converters
-import tempfile
-from cStringIO import StringIO
-
-__all__ = ['Cascade']
-
-def make_cascade(loader, global_conf, catch='404', **local_conf):
-    """
-    Entry point for Paste Deploy configuration
-    
-    Expects configuration like::
-
-        [composit:cascade]
-        use = egg:Paste#cascade
-        # all start with 'app' and are sorted alphabetically
-        app1 = foo
-        app2 = bar
-        ...
-        catch = 404 500 ...
-    """
-    catch = map(int, converters.aslist(catch))
-    apps = []
-    for name, value in local_conf.items():
-        if not name.startswith('app'):
-            raise ValueError(
-                "Bad configuration key %r (=%r); all configuration keys "
-                "must start with 'app'"
-                % (name, value))
-        app = loader.get_app(value, global_conf=global_conf)
-        apps.append((name, app))
-    apps.sort()
-    apps = [app for name, app in apps]
-    return Cascade(apps, catch=catch)
-    
-class Cascade(object):
-
-    """
-    Passed a list of applications, ``Cascade`` will try each of them
-    in turn.  If one returns a status code listed in ``catch`` (by
-    default just ``404 Not Found``) then the next application is
-    tried.
-
-    If all applications fail, then the last application's failure
-    response is used.
-
-    Instances of this class are WSGI applications.
-    """
-
-    def __init__(self, applications, catch=(404,)):
-        self.apps = applications
-        self.catch_codes = {}
-        self.catch_exceptions = []
-        for error in catch:
-            if isinstance(error, str):
-                error = int(error.split(None, 1)[0])
-            if isinstance(error, httpexceptions.HTTPException):
-                exc = error
-                code = error.code
-            else:
-                exc = httpexceptions.get_exception(error)
-                code = error
-            self.catch_codes[code] = exc
-            self.catch_exceptions.append(exc)
-        self.catch_exceptions = tuple(self.catch_exceptions)
-                
-    def __call__(self, environ, start_response):
-        """
-        WSGI application interface
-        """
-        failed = []
-        def repl_start_response(status, headers, exc_info=None):
-            code = int(status.split(None, 1)[0])
-            if code in self.catch_codes:
-                failed.append(None)
-                return _consuming_writer
-            return start_response(status, headers, exc_info)
-
-        try:
-            length = int(environ.get('CONTENT_LENGTH', 0) or 0)
-        except ValueError:
-            length = 0
-        if length > 0:
-            # We have to copy wsgi.input
-            copy_wsgi_input = True
-            if length > 4096 or length < 0:
-                f = tempfile.TemporaryFile()
-                if length < 0:
-                    f.write(environ['wsgi.input'].read())
-                else:
-                    copy_len = length
-                    while copy_len > 0:
-                        chunk = environ['wsgi.input'].read(min(copy_len, 4096))
-                        if not chunk:
-                            raise IOError("Request body truncated")
-                        f.write(chunk)
-                        copy_len -= len(chunk)
-                f.seek(0)
-            else:
-                f = StringIO(environ['wsgi.input'].read(length))
-            environ['wsgi.input'] = f
-        else:
-            copy_wsgi_input = False
-        for app in self.apps[:-1]:
-            environ_copy = environ.copy()
-            if copy_wsgi_input:
-                environ_copy['wsgi.input'].seek(0)
-            failed = []
-            try:
-                v = app(environ_copy, repl_start_response)
-                if not failed:
-                    return v
-                else:
-                    if hasattr(v, 'close'):
-                        # Exhaust the iterator first:
-                        list(v)
-                        # then close:
-                        v.close()
-            except self.catch_exceptions, e:
-                pass
-        if copy_wsgi_input:
-            environ['wsgi.input'].seek(0)
-        return self.apps[-1](environ, start_response)
-
-def _consuming_writer(s):
-    pass
diff --git a/lib/paste/cgiapp.py b/lib/paste/cgiapp.py
@@ -1,271 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-"""
-Application that runs a CGI script.
-"""
-import os
-import subprocess
-try:
-    import select
-except ImportError:
-    select = None
-
-from paste.util import converters
-
-__all__ = ['CGIError', 'CGIApplication']
-
-class CGIError(Exception):
-    """
-    Raised when the CGI script can't be found or doesn't
-    act like a proper CGI script.
-    """
-
-class CGIApplication(object):
-
-    """
-    This object acts as a proxy to a CGI application.  You pass in the
-    script path (``script``), an optional path to search for the
-    script (if the name isn't absolute) (``path``).  If you don't give
-    a path, then ``$PATH`` will be used.
-    """
-
-    def __init__(self, 
-                 global_conf,
-                 script,
-                 path=None,
-                 include_os_environ=True,
-                 query_string=None):
-        if global_conf:
-            raise NotImplemented(
-                "global_conf is no longer supported for CGIApplication "
-                "(use make_cgi_application); please pass None instead")
-        self.script_filename = script
-        if path is None:
-            path = os.environ.get('PATH', '').split(':')
-        self.path = path
-        if '?' in script:
-            assert query_string is None, (
-                "You cannot have '?' in your script name (%r) and also "
-                "give a query_string (%r)" % (script, query_string))
-            script, query_string = script.split('?', 1)
-        if os.path.abspath(script) != script:
-            # relative path
-            for path_dir in self.path:
-                if os.path.exists(os.path.join(path_dir, script)):
-                    self.script = os.path.join(path_dir, script)
-                    break
-            else:
-                raise CGIError(
-                    "Script %r not found in path %r"
-                    % (script, self.path))
-        else:
-            self.script = script
-        self.include_os_environ = include_os_environ
-        self.query_string = query_string
-
-    def __call__(self, environ, start_response):
-        if 'REQUEST_URI' not in environ:
-            environ['REQUEST_URI'] = (
-                environ.get('SCRIPT_NAME', '')
-                + environ.get('PATH_INFO', ''))
-        if self.include_os_environ:
-            cgi_environ = os.environ.copy()
-        else:
-            cgi_environ = {}
-        for name in environ:
-            # Should unicode values be encoded?
-            if (name.upper() == name
-                and isinstance(environ[name], str)):
-                cgi_environ[name] = environ[name]
-        if self.query_string is not None:
-            old = cgi_environ.get('QUERY_STRING', '')
-            if old:
-                old += '&'
-            cgi_environ['QUERY_STRING'] = old + self.query_string
-        cgi_environ['SCRIPT_FILENAME'] = self.script
-        proc = subprocess.Popen(
-            [self.script],
-            stdin=subprocess.PIPE,
-            stdout=subprocess.PIPE,
-            stderr=subprocess.PIPE,
-            env=cgi_environ,
-            cwd=os.path.dirname(self.script),
-            )
-        writer = CGIWriter(environ, start_response)
-        if select:
-            proc_communicate(
-                proc,
-                stdin=StdinReader.from_environ(environ),
-                stdout=writer,
-                stderr=environ['wsgi.errors'])
-        else:
-            stdout, stderr = proc.communicate(StdinReader.from_environ(environ).read())
-            if stderr:
-                environ['wsgi.errors'].write(stderr)
-            writer(stdout)
-        if not writer.headers_finished:
-            start_response(writer.status, writer.headers)
-        return []
-
-class CGIWriter(object):
-
-    def __init__(self, environ, start_response):
-        self.environ = environ
-        self.start_response = start_response
-        self.status = '200 OK'
-        self.headers = []
-        self.headers_finished = False
-        self.writer = None
-        self.buffer = ''
-
-    def write(self, data):
-        if self.headers_finished:
-            self.writer(data)
-            return
-        self.buffer += data
-        while '\n' in self.buffer:
-            if '\r\n' in self.buffer:
-                line1, self.buffer = self.buffer.split('\r\n', 1)
-            else:
-                line1, self.buffer = self.buffer.split('\n', 1)
-            if not line1:
-                self.headers_finished = True
-                self.writer = self.start_response(
-                    self.status, self.headers)
-                self.writer(self.buffer)
-                del self.buffer
-                del self.headers
-                del self.status
-                break
-            elif ':' not in line1:
-                raise CGIError(
-                    "Bad header line: %r" % line1)
-            else:
-                name, value = line1.split(':', 1)
-                value = value.lstrip()
-                name = name.strip()
-                if name.lower() == 'status':
-                    self.status = value
-                else:
-                    self.headers.append((name, value))
-
-class StdinReader(object):
-
-    def __init__(self, stdin, content_length):
-        self.stdin = stdin
-        self.content_length = content_length
-
-    def from_environ(cls, environ):
-        length = environ.get('CONTENT_LENGTH')
-        if length:
-            length = int(length)
-        else:
-            length = 0
-        return cls(environ['wsgi.input'], length)
-
-    from_environ = classmethod(from_environ)
-
-    def read(self, size=None):
-        if not self.content_length:
-            return ''
-        if size is None:
-            text = self.stdin.read(self.content_length)
-        else:
-            text = self.stdin.read(min(self.content_length, size))
-        self.content_length -= len(text)
-        return text
-
-def proc_communicate(proc, stdin=None, stdout=None, stderr=None):
-    """
-    Run the given process, piping input/output/errors to the given
-    file-like objects (which need not be actual file objects, unlike
-    the arguments passed to Popen).  Wait for process to terminate.
-
-    Note: this is taken from the posix version of
-    subprocess.Popen.communicate, but made more general through the
-    use of file-like objects.
-    """
-    read_set = []
-    write_set = []
-    input_buffer = ''
-    trans_nl = proc.universal_newlines and hasattr(open, 'newlines')
-
-    if proc.stdin:
-        # Flush stdio buffer.  This might block, if the user has
-        # been writing to .stdin in an uncontrolled fashion.
-        proc.stdin.flush()
-        if input:
-            write_set.append(proc.stdin)
-        else:
-            proc.stdin.close()
-    else:
-        assert stdin is None
-    if proc.stdout:
-        read_set.append(proc.stdout)
-    else:
-        assert stdout is None
-    if proc.stderr:
-        read_set.append(proc.stderr)
-    else:
-        assert stderr is None
-
-    while read_set or write_set:
-        rlist, wlist, xlist = select.select(read_set, write_set, [])
-
-        if proc.stdin in wlist:
-            # When select has indicated that the file is writable,
-            # we can write up to PIPE_BUF bytes without risk
-            # blocking.  POSIX defines PIPE_BUF >= 512
-            next, input_buffer = input_buffer, ''
-            next_len = 512-len(next)
-            if next_len:
-                next += stdin.read(next_len)
-            if not next:
-                proc.stdin.close()
-                write_set.remove(proc.stdin)
-            else:
-                bytes_written = os.write(proc.stdin.fileno(), next)
-                if bytes_written < len(next):
-                    input_buffer = next[bytes_written:]
-
-        if proc.stdout in rlist:
-            data = os.read(proc.stdout.fileno(), 1024)
-            if data == "":
-                proc.stdout.close()
-                read_set.remove(proc.stdout)
-            if trans_nl:
-                data = proc._translate_newlines(data)
-            stdout.write(data)
-
-        if proc.stderr in rlist:
-            data = os.read(proc.stderr.fileno(), 1024)
-            if data == "":
-                proc.stderr.close()
-                read_set.remove(proc.stderr)
-            if trans_nl:
-                data = proc._translate_newlines(data)
-            stderr.write(data)
-
-    try:
-        proc.wait()
-    except OSError, e:
-        if e.errno != 10:
-            raise
-    
-def make_cgi_application(global_conf, script, path=None, include_os_environ=None,
-                         query_string=None):
-    """
-    Paste Deploy interface for :class:`CGIApplication`
-    
-    This object acts as a proxy to a CGI application.  You pass in the
-    script path (``script``), an optional path to search for the
-    script (if the name isn't absolute) (``path``).  If you don't give
-    a path, then ``$PATH`` will be used.
-    """
-    if path is None:
-        path = global_conf.get('path') or global_conf.get('PATH')
-    include_os_environ = converters.asbool(include_os_environ)
-    return CGIApplication(
-        script, path=path, include_os_environ=include_os_environ,
-        query_string=query_string)
diff --git a/lib/paste/cgitb_catcher.py b/lib/paste/cgitb_catcher.py
@@ -1,116 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-"""
-WSGI middleware
-
-Captures any exceptions and prints a pretty report.  See the `cgitb
-documentation <http://python.org/doc/current/lib/module-cgitb.html>`_
-for more.
-"""
-
-import cgitb
-from cStringIO import StringIO
-import sys
-
-from paste.util import converters
-
-class NoDefault(object):
-    pass
-
-class CgitbMiddleware(object):
-
-    def __init__(self, app,
-                 global_conf=None,
-                 display=NoDefault,
-                 logdir=None,
-                 context=5,
-                 format="html"):
-        self.app = app
-        if global_conf is None:
-            global_conf = {}
-        if display is NoDefault:
-            display = global_conf.get('debug')
-        if isinstance(display, basestring):
-            display = converters.asbool(display)
-        self.display = display
-        self.logdir = logdir
-        self.context = int(context)
-        self.format = format
-
-    def __call__(self, environ, start_response):
-        try:
-            app_iter = self.app(environ, start_response)
-            return self.catching_iter(app_iter, environ)
-        except:
-            exc_info = sys.exc_info()
-            start_response('500 Internal Server Error',
-                           [('content-type', 'text/html')],
-                           exc_info)
-            response = self.exception_handler(exc_info, environ)
-            return [response]
-
-    def catching_iter(self, app_iter, environ):
-        if not app_iter:
-            raise StopIteration
-        error_on_close = False
-        try:
-            for v in app_iter:
-                yield v
-            if hasattr(app_iter, 'close'):
-                error_on_close = True
-                app_iter.close()
-        except:
-            response = self.exception_handler(sys.exc_info(), environ)
-            if not error_on_close and hasattr(app_iter, 'close'):
-                try:
-                    app_iter.close()
-                except:
-                    close_response = self.exception_handler(
-                        sys.exc_info(), environ)
-                    response += (
-                        '<hr noshade>Error in .close():<br>%s'
-                        % close_response)
-            yield response
-
-    def exception_handler(self, exc_info, environ):
-        dummy_file = StringIO()
-        hook = cgitb.Hook(file=dummy_file,
-                          display=self.display,
-                          logdir=self.logdir,
-                          context=self.context,
-                          format=self.format)
-        hook(*exc_info)
-        return dummy_file.getvalue()
-        
-def make_cgitb_middleware(app, global_conf,
-                          display=NoDefault,
-                          logdir=None,
-                          context=5,
-                          format='html'):
-    """
-    Wraps the application in the ``cgitb`` (standard library)
-    error catcher.
-        
-      display:
-        If true (or debug is set in the global configuration)
-        then the traceback will be displayed in the browser
-
-      logdir:
-        Writes logs of all errors in that directory
-
-      context:
-        Number of lines of context to show around each line of
-        source code
-    """
-    from paste.deploy.converters import asbool
-    if display is not NoDefault:
-        display = asbool(display)
-    if 'debug' in global_conf:
-        global_conf['debug'] = asbool(global_conf['debug'])
-    return CgitbMiddleware(
-        app, global_conf=global_conf,
-        display=display,
-        logdir=logdir,
-        context=context,
-        format=format)
diff --git a/lib/paste/config.py b/lib/paste/config.py
@@ -1,120 +0,0 @@
-# (c) 2006 Ian Bicking, Philip Jenvey and contributors
-# Written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""Paste Configuration Middleware and Objects"""
-from paste.registry import RegistryManager, StackedObjectProxy
-
-__all__ = ['DispatchingConfig', 'CONFIG', 'ConfigMiddleware']
-
-class DispatchingConfig(StackedObjectProxy):
-    """
-    This is a configuration object that can be used globally,
-    imported, have references held onto.  The configuration may differ
-    by thread (or may not).
-
-    Specific configurations are registered (and deregistered) either
-    for the process or for threads.
-    """
-    # @@: What should happen when someone tries to add this
-    # configuration to itself?  Probably the conf should become
-    # resolved, and get rid of this delegation wrapper
-
-    def __init__(self, name='DispatchingConfig'):
-        super(DispatchingConfig, self).__init__(name=name)
-        self.__dict__['_process_configs'] = []
-
-    def push_thread_config(self, conf):
-        """
-        Make ``conf`` the active configuration for this thread.
-        Thread-local configuration always overrides process-wide
-        configuration.
-
-        This should be used like::
-
-            conf = make_conf()
-            dispatching_config.push_thread_config(conf)
-            try:
-                ... do stuff ...
-            finally:
-                dispatching_config.pop_thread_config(conf)
-        """
-        self._push_object(conf)
-
-    def pop_thread_config(self, conf=None):
-        """
-        Remove a thread-local configuration.  If ``conf`` is given,
-        it is checked against the popped configuration and an error
-        is emitted if they don't match.
-        """
-        self._pop_object(conf)
-
-    def push_process_config(self, conf):
-        """
-        Like push_thread_config, but applies the configuration to
-        the entire process.
-        """
-        self._process_configs.append(conf)
-
-    def pop_process_config(self, conf=None):
-        self._pop_from(self._process_configs, conf)
-
-    def _pop_from(self, lst, conf):
-        popped = lst.pop()
-        if conf is not None and popped is not conf:
-            raise AssertionError(
-                "The config popped (%s) is not the same as the config "
-                "expected (%s)"
-                % (popped, conf))
-
-    def _current_obj(self):
-        try:
-            return super(DispatchingConfig, self)._current_obj()
-        except TypeError:
-            if self._process_configs:
-                return self._process_configs[-1]
-            raise AttributeError(
-                "No configuration has been registered for this process "
-                "or thread")
-    current = current_conf = _current_obj
-
-CONFIG = DispatchingConfig()
-
-no_config = object()
-class ConfigMiddleware(RegistryManager):
-    """
-    A WSGI middleware that adds a ``paste.config`` key (by default)
-    to the request environment, as well as registering the
-    configuration temporarily (for the length of the request) with
-    ``paste.config.CONFIG`` (or any other ``DispatchingConfig``
-    object).
-    """
-
-    def __init__(self, application, config, dispatching_config=CONFIG,
-                 environ_key='paste.config'):
-        """
-        This delegates all requests to `application`, adding a *copy*
-        of the configuration `config`.
-        """
-        def register_config(environ, start_response):
-            popped_config = environ.get(environ_key, no_config)
-            current_config = environ[environ_key] = config.copy()
-            environ['paste.registry'].register(dispatching_config,
-                                               current_config)
-
-            try:
-                app_iter = application(environ, start_response)
-            finally:
-                if popped_config is no_config:
-                    environ.pop(environ_key, None)
-                else:
-                    environ[environ_key] = popped_config
-            return app_iter
-
-        super(self.__class__, self).__init__(register_config)
-
-def make_config_filter(app, global_conf, **local_conf):
-    conf = global_conf.copy()
-    conf.update(local_conf)
-    return ConfigMiddleware(app, conf)
-
-make_config_middleware = ConfigMiddleware.__doc__
diff --git a/lib/paste/debug/__init__.py b/lib/paste/debug/__init__.py
@@ -1,5 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-Package for debugging and development tools
-"""
diff --git a/lib/paste/debug/debugapp.py b/lib/paste/debug/debugapp.py
@@ -1,79 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-# (c) 2005 Clark C. Evans
-# This module is part of the Python Paste Project and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-# This code was written with funding by http://prometheusresearch.com
-"""
-Various Applications for Debugging/Testing Purposes
-"""
-
-import time
-__all__ = ['SimpleApplication', 'SlowConsumer']
-
-
-class SimpleApplication(object):
-    """
-    Produces a simple web page
-    """
-    def __call__(self, environ, start_response):
-        body = "<html><body>simple</body></html>"
-        start_response("200 OK", [('Content-Type', 'text/html'),
-                                  ('Content-Length', str(len(body)))])
-        return [body]
-
-class SlowConsumer(object):
-    """
-    Consumes an upload slowly...
-
-    NOTE: This should use the iterator form of ``wsgi.input``,
-          but it isn't implemented in paste.httpserver.
-    """
-    def __init__(self, chunk_size = 4096, delay = 1, progress = True):
-        self.chunk_size = chunk_size
-        self.delay = delay
-        self.progress = True
-
-    def __call__(self, environ, start_response):
-        size = 0
-        total  = environ.get('CONTENT_LENGTH')
-        if total:
-            remaining = int(total)
-            while remaining > 0:
-                if self.progress:
-                    print "%s of %s remaining" % (remaining, total)
-                if remaining > 4096:
-                    chunk = environ['wsgi.input'].read(4096)
-                else:
-                    chunk = environ['wsgi.input'].read(remaining)
-                if not chunk:
-                    break
-                size += len(chunk)
-                remaining -= len(chunk)
-                if self.delay:
-                    time.sleep(self.delay)
-            body = "<html><body>%d bytes</body></html>" % size
-        else:
-            body = ('<html><body>\n'
-                '<form method="post" enctype="multipart/form-data">\n'
-                '<input type="file" name="file">\n'
-                '<input type="submit" >\n'
-                '</form></body></html>\n')
-        print "bingles"
-        start_response("200 OK", [('Content-Type', 'text/html'),
-                                  ('Content-Length', len(body))])
-        return [body]
-
-def make_test_app(global_conf):
-    return SimpleApplication()
-
-make_test_app.__doc__ = SimpleApplication.__doc__
-
-def make_slow_app(global_conf, chunk_size=4096, delay=1, progress=True):
-    from paste.deploy.converters import asbool
-    return SlowConsumer(
-        chunk_size=int(chunk_size),
-        delay=int(delay),
-        progress=asbool(progress))
-
-make_slow_app.__doc__ = SlowConsumer.__doc__
diff --git a/lib/paste/debug/doctest_webapp.py b/lib/paste/debug/doctest_webapp.py
@@ -1,435 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-#!/usr/bin/env python2.4
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-"""
-These are functions for use when doctest-testing a document.
-"""
-
-try:
-    import subprocess
-except ImportError:
-    from paste.util import subprocess24 as subprocess
-import doctest
-import os
-import sys
-import shutil
-import re
-import cgi
-import rfc822
-from cStringIO import StringIO
-from paste.util import PySourceColor
-
-
-here = os.path.abspath(__file__)
-paste_parent = os.path.dirname(
-    os.path.dirname(os.path.dirname(here)))
-
-def run(command):
-    data = run_raw(command)
-    if data:
-        print data
-
-def run_raw(command):
-    """
-    Runs the string command, returns any output.
-    """
-    proc = subprocess.Popen(command, shell=True,
-                            stderr=subprocess.STDOUT,
-                            stdout=subprocess.PIPE, env=_make_env())
-    data = proc.stdout.read()
-    proc.wait()
-    while data.endswith('\n') or data.endswith('\r'):
-        data = data[:-1]
-    if data:
-        data = '\n'.join(
-            [l for l in data.splitlines() if l])
-        return data
-    else:
-        return ''
-
-def run_command(command, name, and_print=False):
-    output = run_raw(command)
-    data = '$ %s\n%s' % (command, output)
-    show_file('shell-command', name, description='shell transcript',
-              data=data)
-    if and_print and output:
-        print output
-
-def _make_env():
-    env = os.environ.copy()
-    env['PATH'] = (env.get('PATH', '')
-                   + ':'
-                   + os.path.join(paste_parent, 'scripts')
-                   + ':'
-                   + os.path.join(paste_parent, 'paste', '3rd-party',
-                                  'sqlobject-files', 'scripts'))
-    env['PYTHONPATH'] = (env.get('PYTHONPATH', '')
-                         + ':'
-                         + paste_parent)
-    return env
-
-def clear_dir(dir):
-    """
-    Clears (deletes) the given directory
-    """
-    shutil.rmtree(dir, True)
-
-def ls(dir=None, recurse=False, indent=0):
-    """
-    Show a directory listing
-    """
-    dir = dir or os.getcwd()
-    fns = os.listdir(dir)
-    fns.sort()
-    for fn in fns:
-        full = os.path.join(dir, fn)
-        if os.path.isdir(full):
-            fn = fn + '/'
-        print ' '*indent + fn
-        if os.path.isdir(full) and recurse:
-            ls(dir=full, recurse=True, indent=indent+2)
-
-default_app = None
-default_url = None
-
-def set_default_app(app, url):
-    global default_app
-    global default_url
-    default_app = app
-    default_url = url
-
-def resource_filename(fn):
-    """
-    Returns the filename of the resource -- generally in the directory
-    resources/DocumentName/fn
-    """
-    return os.path.join(
-        os.path.dirname(sys.testing_document_filename),
-        'resources',
-        os.path.splitext(os.path.basename(sys.testing_document_filename))[0],
-        fn)
-
-def show(path_info, example_name):
-    fn = resource_filename(example_name + '.html')
-    out = StringIO()
-    assert default_app is not None, (
-        "No default_app set")
-    url = default_url + path_info
-    out.write('<span class="doctest-url"><a href="%s">%s</a></span><br>\n'
-              % (url, url))
-    out.write('<div class="doctest-example">\n')
-    proc = subprocess.Popen(
-        ['paster', 'serve' '--server=console', '--no-verbose',
-         '--url=' + path_info],
-        stderr=subprocess.PIPE,
-        stdout=subprocess.PIPE,
-        env=_make_env())
-    stdout, errors = proc.communicate()
-    stdout = StringIO(stdout)
-    headers = rfc822.Message(stdout)
-    content = stdout.read()
-    for header, value in headers.items():
-        if header.lower() == 'status' and int(value.split()[0]) == 200:
-            continue
-        if header.lower() in ('content-type', 'content-length'):
-            continue
-        if (header.lower() == 'set-cookie'
-            and value.startswith('_SID_')):
-            continue
-        out.write('<span class="doctest-header">%s: %s</span><br>\n'
-                  % (header, value))
-    lines = [l for l in content.splitlines() if l.strip()]
-    for line in lines:
-        out.write(line + '\n')
-    if errors:
-        out.write('<pre class="doctest-errors">%s</pre>'
-                  % errors)
-    out.write('</div>\n')
-    result = out.getvalue()
-    if not os.path.exists(fn):
-        f = open(fn, 'wb')
-        f.write(result)
-        f.close()
-    else:
-        f = open(fn, 'rb')
-        expected = f.read()
-        f.close()
-        if not html_matches(expected, result):
-            print 'Pages did not match.  Expected from %s:' % fn
-            print '-'*60
-            print expected
-            print '='*60
-            print 'Actual output:'
-            print '-'*60
-            print result
-
-def html_matches(pattern, text):
-    regex = re.escape(pattern)
-    regex = regex.replace(r'\.\.\.', '.*')
-    regex = re.sub(r'0x[0-9a-f]+', '.*', regex)
-    regex = '^%s$' % regex
-    return re.search(regex, text)
-
-def convert_docstring_string(data):
-    if data.startswith('\n'):
-        data = data[1:]
-    lines = data.splitlines()
-    new_lines = []
-    for line in lines:
-        if line.rstrip() == '.':
-            new_lines.append('')
-        else:
-            new_lines.append(line)
-    data = '\n'.join(new_lines) + '\n'
-    return data
-
-def create_file(path, version, data):
-    data = convert_docstring_string(data)
-    write_data(path, data)
-    show_file(path, version)
-
-def append_to_file(path, version, data):
-    data = convert_docstring_string(data)
-    f = open(path, 'a')
-    f.write(data)
-    f.close()
-    # I think these appends can happen so quickly (in less than a second)
-    # that the .pyc file doesn't appear to be expired, even though it
-    # is after we've made this change; so we have to get rid of the .pyc
-    # file:
-    if path.endswith('.py'):
-        pyc_file = path + 'c'
-        if os.path.exists(pyc_file):
-            os.unlink(pyc_file)
-    show_file(path, version, description='added to %s' % path,
-              data=data)
-
-def show_file(path, version, description=None, data=None):
-    ext = os.path.splitext(path)[1]
-    if data is None:
-        f = open(path, 'rb')
-        data = f.read()
-        f.close()
-    if ext == '.py':
-        html = ('<div class="source-code">%s</div>' 
-                % PySourceColor.str2html(data, PySourceColor.dark))
-    else:
-        html = '<pre class="source-code">%s</pre>' % cgi.escape(data, 1)
-    html = '<span class="source-filename">%s</span><br>%s' % (
-        description or path, html)
-    write_data(resource_filename('%s.%s.gen.html' % (path, version)),
-               html)
-
-def call_source_highlight(input, format):
-    proc = subprocess.Popen(['source-highlight', '--out-format=html',
-                             '--no-doc', '--css=none',
-                             '--src-lang=%s' % format], shell=False,
-                            stdout=subprocess.PIPE)
-    stdout, stderr = proc.communicate(input)
-    result = stdout
-    proc.wait()
-    return result
-
-
-def write_data(path, data):
-    dir = os.path.dirname(os.path.abspath(path))
-    if not os.path.exists(dir):
-        os.makedirs(dir)
-    f = open(path, 'wb')
-    f.write(data)
-    f.close()
-    
-
-def change_file(path, changes):
-    f = open(os.path.abspath(path), 'rb')
-    lines = f.readlines()
-    f.close()
-    for change_type, line, text in changes:
-        if change_type == 'insert':
-            lines[line:line] = [text]
-        elif change_type == 'delete':
-            lines[line:text] = []
-        else:
-            assert 0, (
-                "Unknown change_type: %r" % change_type)
-    f = open(path, 'wb')
-    f.write(''.join(lines))
-    f.close()
-
-class LongFormDocTestParser(doctest.DocTestParser):
-
-    """
-    This parser recognizes some reST comments as commands, without
-    prompts or expected output, like:
-
-    .. run:
-
-        do_this(...
-        ...)
-    """
-
-    _EXAMPLE_RE = re.compile(r"""
-        # Source consists of a PS1 line followed by zero or more PS2 lines.
-        (?: (?P<source>
-                (?:^(?P<indent> [ ]*) >>>    .*)    # PS1 line
-                (?:\n           [ ]*  \.\.\. .*)*)  # PS2 lines
-            \n?
-            # Want consists of any non-blank lines that do not start with PS1.
-            (?P<want> (?:(?![ ]*$)    # Not a blank line
-                         (?![ ]*>>>)  # Not a line starting with PS1
-                         .*$\n?       # But any other line
-                      )*))
-        | 
-        (?: # This is for longer commands that are prefixed with a reST
-            # comment like '.. run:' (two colons makes that a directive).
-            # These commands cannot have any output.
-
-            (?:^\.\.[ ]*(?P<run>run):[ ]*\n) # Leading command/command
-            (?:[ ]*\n)?         # Blank line following
-            (?P<runsource>
-                (?:(?P<runindent> [ ]+)[^ ].*$)
-                (?:\n [ ]+ .*)*)
-            )
-        |
-        (?: # This is for shell commands
-
-            (?P<shellsource>
-                (?:^(P<shellindent> [ ]*) [$] .*)   # Shell line
-                (?:\n               [ ]*  [>] .*)*) # Continuation
-            \n?
-            # Want consists of any non-blank lines that do not start with $
-            (?P<shellwant> (?:(?![ ]*$)
-                              (?![ ]*[$]$)
-                              .*$\n?
-                           )*))
-        """, re.MULTILINE | re.VERBOSE)
-
-    def _parse_example(self, m, name, lineno):
-        r"""
-        Given a regular expression match from `_EXAMPLE_RE` (`m`),
-        return a pair `(source, want)`, where `source` is the matched
-        example's source code (with prompts and indentation stripped);
-        and `want` is the example's expected output (with indentation
-        stripped).
-
-        `name` is the string's name, and `lineno` is the line number
-        where the example starts; both are used for error messages.
-
-        >>> def parseit(s):
-        ...     p = LongFormDocTestParser()
-        ...     return p._parse_example(p._EXAMPLE_RE.search(s), '<string>', 1)
-        >>> parseit('>>> 1\n1')
-        ('1', {}, '1', None)
-        >>> parseit('>>> (1\n... +1)\n2')
-        ('(1\n+1)', {}, '2', None)
-        >>> parseit('.. run:\n\n    test1\n    test2\n')
-        ('test1\ntest2', {}, '', None)
-        """
-        # Get the example's indentation level.
-        runner = m.group('run') or ''
-        indent = len(m.group('%sindent' % runner))
-        
-        # Divide source into lines; check that they're properly
-        # indented; and then strip their indentation & prompts.
-        source_lines = m.group('%ssource' % runner).split('\n')
-        if runner:
-            self._check_prefix(source_lines[1:], ' '*indent, name, lineno)
-        else:
-            self._check_prompt_blank(source_lines, indent, name, lineno)
-            self._check_prefix(source_lines[2:], ' '*indent + '.', name, lineno)
-        if runner:
-            source = '\n'.join([sl[indent:] for sl in source_lines])
-        else:
-            source = '\n'.join([sl[indent+4:] for sl in source_lines])
-
-        if runner:
-            want = ''
-            exc_msg = None
-        else:
-            # Divide want into lines; check that it's properly indented; and
-            # then strip the indentation.  Spaces before the last newline should
-            # be preserved, so plain rstrip() isn't good enough.
-            want = m.group('want')
-            want_lines = want.split('\n')
-            if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
-                del want_lines[-1]  # forget final newline & spaces after it
-            self._check_prefix(want_lines, ' '*indent, name,
-                               lineno + len(source_lines))
-            want = '\n'.join([wl[indent:] for wl in want_lines])
-
-            # If `want` contains a traceback message, then extract it.
-            m = self._EXCEPTION_RE.match(want)
-            if m:
-                exc_msg = m.group('msg')
-            else:
-                exc_msg = None
-
-        # Extract options from the source.
-        options = self._find_options(source, name, lineno)
-
-        return source, options, want, exc_msg
-
-
-    def parse(self, string, name='<string>'):
-        """
-        Divide the given string into examples and intervening text,
-        and return them as a list of alternating Examples and strings.
-        Line numbers for the Examples are 0-based.  The optional
-        argument `name` is a name identifying this string, and is only
-        used for error messages.
-        """
-        string = string.expandtabs()
-        # If all lines begin with the same indentation, then strip it.
-        min_indent = self._min_indent(string)
-        if min_indent > 0:
-            string = '\n'.join([l[min_indent:] for l in string.split('\n')])
-
-        output = []
-        charno, lineno = 0, 0
-        # Find all doctest examples in the string:
-        for m in self._EXAMPLE_RE.finditer(string):
-            # Add the pre-example text to `output`.
-            output.append(string[charno:m.start()])
-            # Update lineno (lines before this example)
-            lineno += string.count('\n', charno, m.start())
-            # Extract info from the regexp match.
-            (source, options, want, exc_msg) = \
-                     self._parse_example(m, name, lineno)
-            # Create an Example, and add it to the list.
-            if not self._IS_BLANK_OR_COMMENT(source):
-                # @@: Erg, this is the only line I need to change...
-                output.append(doctest.Example(
-                    source, want, exc_msg,
-                    lineno=lineno,
-                    indent=min_indent+len(m.group('indent') or m.group('runindent')),
-                    options=options))
-            # Update lineno (lines inside this example)
-            lineno += string.count('\n', m.start(), m.end())
-            # Update charno.
-            charno = m.end()
-        # Add any remaining post-example text to `output`.
-        output.append(string[charno:])
-        return output
-
-
-
-if __name__ == '__main__':
-    if sys.argv[1:] and sys.argv[1] == 'doctest':
-        doctest.testmod()
-        sys.exit()
-    if not paste_parent in sys.path:
-        sys.path.append(paste_parent)
-    for fn in sys.argv[1:]:
-        fn = os.path.abspath(fn)
-        # @@: OK, ick; but this module gets loaded twice
-        sys.testing_document_filename = fn
-        doctest.testfile(
-            fn, module_relative=False,
-            optionflags=doctest.ELLIPSIS|doctest.REPORT_ONLY_FIRST_FAILURE,
-            parser=LongFormDocTestParser())
-        new = os.path.splitext(fn)[0] + '.html'
-        assert new != fn
-        os.system('rst2html.py %s > %s' % (fn, new))
diff --git a/lib/paste/debug/fsdiff.py b/lib/paste/debug/fsdiff.py
@@ -1,409 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-Module to find differences over time in a filesystem
-
-Basically this takes a snapshot of a directory, then sees what changes
-were made.  The contents of the files are not checked, so you can
-detect that the content was changed, but not what the old version of
-the file was.
-"""
-
-import os
-from fnmatch import fnmatch
-from datetime import datetime
-from paste.util.UserDict24 import IterableUserDict
-import operator
-import re
-
-__all__ = ['Diff', 'Snapshot', 'File', 'Dir', 'report_expected_diffs',
-           'show_diff']
-
-class Diff(object):
-
-    """
-    Represents the difference between two snapshots
-    """
-
-    def __init__(self, before, after):
-        self.before = before
-        self.after = after
-        self._calculate()
-
-    def _calculate(self):
-        before = self.before.data
-        after = self.after.data
-        self.deleted = {}
-        self.updated = {}
-        self.created = after.copy()
-        for path, f in before.items():
-            if path not in after:
-                self.deleted[path] = f
-                continue
-            del self.created[path]
-            if f.mtime < after[path].mtime:
-                self.updated[path] = after[path]
-
-    def __str__(self):
-        return self.report()
-
-    def report(self, header=True, dates=False):
-        s = []
-        if header:
-            s.append('Difference in %s from %s to %s:' %
-                     (self.before.base_path,
-                      self.before.calculated,
-                      self.after.calculated))
-        for name, files, show_size in [
-            ('created', self.created, True),
-            ('deleted', self.deleted, True),
-            ('updated', self.updated, True)]:
-            if files:
-                s.append('-- %s: -------------------' % name)
-                files = files.items()
-                files.sort()
-                last = ''
-                for path, f in files:
-                    t = '  %s' % _space_prefix(last, path, indent=4,
-                                               include_sep=False)
-                    last = path
-                    if show_size and f.size != 'N/A':
-                        t += '  (%s bytes)' % f.size
-                    if dates:
-                        parts = []
-                        if self.before.get(path):
-                            parts.append(self.before[path].mtime)
-                        if self.after.get(path):
-                            parts.append(self.after[path].mtime)
-                        t += ' (mtime: %s)' % ('->'.join(map(repr, parts)))
-                    s.append(t)
-        if len(s) == 1:
-            s.append('  (no changes)')
-        return '\n'.join(s)
-
-class Snapshot(IterableUserDict):
-
-    """
-    Represents a snapshot of a set of files.  Has a dictionary-like
-    interface, keyed relative to ``base_path``
-    """
-
-    def __init__(self, base_path, files=None, ignore_wildcards=(),
-                 ignore_paths=(), ignore_hidden=True):
-        self.base_path = base_path
-        self.ignore_wildcards = ignore_wildcards
-        self.ignore_hidden = ignore_hidden
-        self.ignore_paths = ignore_paths
-        self.calculated = None
-        self.data = files or {}
-        if files is None:
-            self.find_files()
-
-    ############################################################
-    ## File finding
-    ############################################################
-
-    def find_files(self):
-        """
-        Find all the files under the base path, and put them in
-        ``self.data``
-        """
-        self._find_traverse('', self.data)
-        self.calculated = datetime.now()
-
-    def _ignore_file(self, fn):
-        if fn in self.ignore_paths:
-            return True
-        if self.ignore_hidden and os.path.basename(fn).startswith('.'):
-            return True
-        for pat in self.ignore_wildcards:
-            if fnmatch(fn, pat):
-                return True
-        return False
-
-    def _ignore_file(self, fn):
-        if fn in self.ignore_paths:
-            return True
-        if self.ignore_hidden and os.path.basename(fn).startswith('.'):
-            return True
-        return False
-
-    def _find_traverse(self, path, result):
-        full = os.path.join(self.base_path, path)
-        if os.path.isdir(full):
-            if path:
-                # Don't actually include the base path
-                result[path] = Dir(self.base_path, path)
-            for fn in os.listdir(full):
-                fn = os.path.join(path, fn)
-                if self._ignore_file(fn):
-                    continue
-                self._find_traverse(fn, result)
-        else:
-            result[path] = File(self.base_path, path)
-
-    def __repr__(self):
-        return '<%s in %r from %r>' % (
-            self.__class__.__name__, self.base_path,
-            self.calculated or '(no calculation done)')
-
-    def compare_expected(self, expected, comparison=operator.eq,
-                         differ=None, not_found=None,
-                         include_success=False):
-        """
-        Compares a dictionary of ``path: content`` to the
-        found files.  Comparison is done by equality, or the
-        ``comparison(actual_content, expected_content)`` function given.
-
-        Returns dictionary of differences, keyed by path.  Each
-        difference is either noted, or the output of
-        ``differ(actual_content, expected_content)`` is given.
-
-        If a file does not exist and ``not_found`` is given, then
-        ``not_found(path)`` is put in.
-        """
-        result = {}
-        for path in expected:
-            orig_path = path
-            path = path.strip('/')
-            if path not in self.data:
-                if not_found:
-                    msg = not_found(path)
-                else:
-                    msg = 'not found'
-                result[path] = msg
-                continue
-            expected_content = expected[orig_path]
-            file = self.data[path]
-            actual_content = file.bytes
-            if not comparison(actual_content, expected_content):
-                if differ:
-                    msg = differ(actual_content, expected_content)
-                else:
-                    if len(actual_content) < len(expected_content):
-                        msg = 'differ (%i bytes smaller)' % (
-                            len(expected_content) - len(actual_content))
-                    elif len(actual_content) > len(expected_content):
-                        msg = 'differ (%i bytes larger)' % (
-                            len(actual_content) - len(expected_content))
-                    else:
-                        msg = 'diff (same size)'
-                result[path] = msg
-            elif include_success:
-                result[path] = 'same!'
-        return result
-
-    def diff_to_now(self):
-        return Diff(self, self.clone())
-
-    def clone(self):
-        return self.__class__(base_path=self.base_path,
-                              ignore_wildcards=self.ignore_wildcards,
-                              ignore_paths=self.ignore_paths,
-                              ignore_hidden=self.ignore_hidden)
-
-class File(object):
-
-    """
-    Represents a single file found as the result of a command.
-
-    Has attributes:
-
-    ``path``:
-        The path of the file, relative to the ``base_path``
-
-    ``full``:
-        The full path
-
-    ``stat``:
-        The results of ``os.stat``.  Also ``mtime`` and ``size``
-        contain the ``.st_mtime`` and ``st_size`` of the stat.
-
-    ``bytes``:
-        The contents of the file.
-
-    You may use the ``in`` operator with these objects (tested against
-    the contents of the file), and the ``.mustcontain()`` method.
-    """
-
-    file = True
-    dir = False
-
-    def __init__(self, base_path, path):
-        self.base_path = base_path
-        self.path = path
-        self.full = os.path.join(base_path, path)
-        self.stat = os.stat(self.full)
-        self.mtime = self.stat.st_mtime
-        self.size = self.stat.st_size
-        self._bytes = None
-
-    def bytes__get(self):
-        if self._bytes is None:
-            f = open(self.full, 'rb')
-            self._bytes = f.read()
-            f.close()
-        return self._bytes
-    bytes = property(bytes__get)
-
-    def __contains__(self, s):
-        return s in self.bytes
-
-    def mustcontain(self, s):
-        __tracebackhide__ = True
-        bytes = self.bytes
-        if s not in bytes:
-            print 'Could not find %r in:' % s
-            print bytes
-            assert s in bytes
-
-    def __repr__(self):
-        return '<%s %s:%s>' % (
-            self.__class__.__name__,
-            self.base_path, self.path)
-
-class Dir(File):
-
-    """
-    Represents a directory created by a command.
-    """
-
-    file = False
-    dir = True
-
-    def __init__(self, base_path, path):
-        self.base_path = base_path
-        self.path = path
-        self.full = os.path.join(base_path, path)
-        self.size = 'N/A'
-        self.mtime = 'N/A'
-
-    def __repr__(self):
-        return '<%s %s:%s>' % (
-            self.__class__.__name__,
-            self.base_path, self.path)
-
-    def bytes__get(self):
-        raise NotImplementedError(
-            "Directory %r doesn't have content" % self)
-
-    bytes = property(bytes__get)
-    
-
-def _space_prefix(pref, full, sep=None, indent=None, include_sep=True):
-    """
-    Anything shared by pref and full will be replaced with spaces
-    in full, and full returned.
-
-    Example::
-
-        >>> _space_prefix('/foo/bar', '/foo')
-        '    /bar'
-    """
-    if sep is None:
-        sep = os.path.sep
-    pref = pref.split(sep)
-    full = full.split(sep)
-    padding = []
-    while pref and full and pref[0] == full[0]:
-        if indent is None:
-            padding.append(' ' * (len(full[0]) + len(sep)))
-        else:
-            padding.append(' ' * indent)
-        full.pop(0)
-        pref.pop(0)
-    if padding:
-        if include_sep:
-            return ''.join(padding) + sep + sep.join(full)
-        else:
-            return ''.join(padding) + sep.join(full)
-    else:
-        return sep.join(full)
-
-def report_expected_diffs(diffs, colorize=False):
-    """
-    Takes the output of compare_expected, and returns a string
-    description of the differences.
-    """
-    if not diffs:
-        return 'No differences'
-    diffs = diffs.items()
-    diffs.sort()
-    s = []
-    last = ''
-    for path, desc in diffs:
-        t = _space_prefix(last, path, indent=4, include_sep=False)
-        if colorize:
-            t = color_line(t, 11)
-        last = path
-        if len(desc.splitlines()) > 1:
-            cur_indent = len(re.search(r'^[ ]*', t).group(0))
-            desc = indent(cur_indent+2, desc)
-            if colorize:
-                t += '\n'
-                for line in desc.splitlines():
-                    if line.strip().startswith('+'):
-                        line = color_line(line, 10)
-                    elif line.strip().startswith('-'):
-                        line = color_line(line, 9)
-                    else:
-                        line = color_line(line, 14)
-                    t += line+'\n'
-            else:
-                t += '\n' + desc
-        else:
-            t += ' '+desc
-        s.append(t)
-    s.append('Files with differences: %s' % len(diffs))
-    return '\n'.join(s)
-
-def color_code(foreground=None, background=None):
-    """
-    0  black
-    1  red
-    2  green
-    3  yellow
-    4  blue
-    5  magenta (purple)
-    6  cyan
-    7  white (gray)
-
-    Add 8 to get high-intensity
-    """
-    if foreground is None and background is None:
-        # Reset
-        return '\x1b[0m'
-    codes = []
-    if foreground is None:
-        codes.append('[39m')
-    elif foreground > 7:
-        codes.append('[1m')
-        codes.append('[%im' % (22+foreground))
-    else:
-        codes.append('[%im' % (30+foreground))
-    if background is None:
-        codes.append('[49m')
-    else:
-        codes.append('[%im' % (40+background))
-    return '\x1b' + '\x1b'.join(codes)
-
-def color_line(line, foreground=None, background=None):
-    match = re.search(r'^(\s*)', line)
-    return (match.group(1) + color_code(foreground, background)
-            + line[match.end():] + color_code())
-
-def indent(indent, text):
-    return '\n'.join(
-        [' '*indent + l for l in text.splitlines()])
-
-def show_diff(actual_content, expected_content):
-    actual_lines = [l.strip() for l in actual_content.splitlines()
-                    if l.strip()]
-    expected_lines = [l.strip() for l in expected_content.splitlines()
-                      if l.strip()]
-    if len(actual_lines) == len(expected_lines) == 1:
-        return '%r not %r' % (actual_lines[0], expected_lines[0])
-    if not actual_lines:
-        return 'Empty; should have:\n'+expected_content
-    import difflib
-    return '\n'.join(difflib.ndiff(actual_lines, expected_lines))
diff --git a/lib/paste/debug/prints.py b/lib/paste/debug/prints.py
@@ -1,148 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-Middleware that displays everything that is printed inline in
-application pages.
-
-Anything printed during the request will get captured and included on
-the page.  It will usually be included as a floating element in the
-top right hand corner of the page.  If you want to override this
-you can include a tag in your template where it will be placed::
-
-  <pre id="paste-debug-prints"></pre>
-
-You might want to include ``style="white-space: normal"``, as all the
-whitespace will be quoted, and this allows the text to wrap if
-necessary.
-
-"""
-
-from cStringIO import StringIO
-import re
-import cgi
-from paste.util import threadedprint
-from paste import wsgilib
-from paste import response
-import sys
-
-_threadedprint_installed = False
-
-__all__ = ['PrintDebugMiddleware']
-
-class TeeFile(object):
-
-    def __init__(self, files):
-        self.files = files
-
-    def write(self, v):
-        if isinstance(v, unicode):
-            # WSGI is picky in this case
-            v = str(v)
-        for file in self.files:
-            file.write(v)
-
-class PrintDebugMiddleware(object):
-
-    """
-    This middleware captures all the printed statements, and inlines
-    them in HTML pages, so that you can see all the (debug-intended)
-    print statements in the page itself.
-
-    There are two keys added to the environment to control this:
-    ``environ['paste.printdebug_listeners']`` is a list of functions
-    that will be called everytime something is printed.
-
-    ``environ['paste.remove_printdebug']`` is a function that, if
-    called, will disable printing of output for that request.
-
-    If you have ``replace_stdout=True`` then stdout is replaced, not
-    captured.
-    """
-
-    log_template = (
-        '<pre style="width: 40%%; border: 2px solid #000; white-space: normal; '
-        'background-color: #ffd; color: #000; float: right;">'
-        '<b style="border-bottom: 1px solid #000">Log messages</b><br>'
-        '%s</pre>')
-
-    def __init__(self, app, global_conf=None, force_content_type=False,
-                 print_wsgi_errors=True, replace_stdout=False):
-        # @@: global_conf should be handled separately and only for
-        # the entry point
-        self.app = app
-        self.force_content_type = force_content_type
-        if isinstance(print_wsgi_errors, basestring):
-            from paste.deploy.converters import asbool
-            print_wsgi_errors = asbool(print_wsgi_errors)
-        self.print_wsgi_errors = print_wsgi_errors
-        self.replace_stdout = replace_stdout
-        self._threaded_print_stdout = None
-
-    def __call__(self, environ, start_response):
-        global _threadedprint_installed
-        if environ.get('paste.testing'):
-            # In a testing environment this interception isn't
-            # useful:
-            return self.app(environ, start_response)
-        if (not _threadedprint_installed
-            or self._threaded_print_stdout is not sys.stdout):
-            # @@: Not strictly threadsafe
-            _threadedprint_installed = True
-            threadedprint.install(leave_stdout=not self.replace_stdout)
-            self._threaded_print_stdout = sys.stdout
-        removed = []
-        def remove_printdebug():
-            removed.append(None)
-        environ['paste.remove_printdebug'] = remove_printdebug
-        logged = StringIO()
-        listeners = [logged]
-        environ['paste.printdebug_listeners'] = listeners
-        if self.print_wsgi_errors:
-            listeners.append(environ['wsgi.errors'])
-        replacement_stdout = TeeFile(listeners)
-        threadedprint.register(replacement_stdout)
-        try:
-            status, headers, body = wsgilib.intercept_output(
-                environ, self.app)
-            if status is None:
-                # Some error occurred
-                status = '500 Server Error'
-                headers = [('Content-type', 'text/html')]
-                start_response(status, headers)
-                if not body:
-                    body = 'An error occurred'
-            content_type = response.header_value(headers, 'content-type')
-            if (removed or
-                (not self.force_content_type and
-                 (not content_type
-                  or not content_type.startswith('text/html')))):
-                if replacement_stdout == logged:
-                    # Then the prints will be lost, unless...
-                    environ['wsgi.errors'].write(logged.getvalue())
-                start_response(status, headers)
-                return [body]
-            response.remove_header(headers, 'content-length')
-            body = self.add_log(body, logged.getvalue())
-            start_response(status, headers)
-            return [body]
-        finally:
-            threadedprint.deregister()
-
-    _body_re = re.compile(r'<body[^>]*>', re.I)
-    _explicit_re = re.compile(r'<pre\s*[^>]*id="paste-debug-prints".*?>',
-                              re.I+re.S)
-    
-    def add_log(self, html, log):
-        if not log:
-            return html
-        text = cgi.escape(log)
-        text = text.replace('\n', '<br>')
-        text = text.replace('  ', '&nbsp; ')
-        match = self._explicit_re.search(html)
-        if not match:
-            text = self.log_template % text
-            match = self._body_re.search(html)
-        if not match:
-            return text + html
-        else:
-            return html[:match.end()] + text + html[match.end():]
diff --git a/lib/paste/debug/profile.py b/lib/paste/debug/profile.py
@@ -1,227 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-Middleware that profiles the request and displays profiling
-information at the bottom of each page.
-"""
-
-
-import sys
-import os
-import hotshot
-import hotshot.stats
-import threading
-import cgi
-import time
-from cStringIO import StringIO
-from paste import response
-
-__all__ = ['ProfileMiddleware', 'profile_decorator']
-
-class ProfileMiddleware(object):
-
-    """
-    Middleware that profiles all requests.
-
-    All HTML pages will have profiling information appended to them.
-    The data is isolated to that single request, and does not include
-    data from previous requests.
-
-    This uses the ``hotshot`` module, which affects performance of the
-    application.  It also runs in a single-threaded mode, so it is
-    only usable in development environments.
-    """
-
-    style = ('clear: both; background-color: #ff9; color: #000; '
-             'border: 2px solid #000; padding: 5px;')
-
-    def __init__(self, app, global_conf=None,
-                 log_filename='profile.log.tmp',
-                 limit=40):
-        self.app = app
-        self.lock = threading.Lock()
-        self.log_filename = log_filename
-        self.limit = limit
-
-    def __call__(self, environ, start_response):
-        catch_response = []
-        body = []
-        def replace_start_response(status, headers, exc_info=None):
-            catch_response.extend([status, headers])
-            start_response(status, headers, exc_info)
-            return body.append
-        def run_app():
-            app_iter = self.app(environ, replace_start_response)
-            try:
-                body.extend(app_iter)
-            finally:
-                if hasattr(app_iter, 'close'):
-                    app_iter.close()
-        self.lock.acquire()
-        try:
-            prof = hotshot.Profile(self.log_filename)
-            prof.addinfo('URL', environ.get('PATH_INFO', ''))
-            try:
-                prof.runcall(run_app)
-            finally:
-                prof.close()
-            body = ''.join(body)
-            headers = catch_response[1]
-            content_type = response.header_value(headers, 'content-type')
-            if content_type is None or not content_type.startswith('text/html'):
-                # We can't add info to non-HTML output
-                return [body]
-            stats = hotshot.stats.load(self.log_filename)
-            stats.strip_dirs()
-            stats.sort_stats('time', 'calls')
-            output = capture_output(stats.print_stats, self.limit)
-            output_callers = capture_output(
-                stats.print_callers, self.limit)
-            body += '<pre style="%s">%s\n%s</pre>' % (
-                self.style, cgi.escape(output), cgi.escape(output_callers))
-            return [body]
-        finally:
-            self.lock.release()
-
-def capture_output(func, *args, **kw):
-    # Not threadsafe! (that's okay when ProfileMiddleware uses it,
-    # though, since it synchronizes itself.)
-    out = StringIO()
-    old_stdout = sys.stdout
-    sys.stdout = out
-    try:
-        func(*args, **kw)
-    finally:
-        sys.stdout = old_stdout
-    return out.getvalue()
-
-def profile_decorator(**options):
-
-    """
-    Profile a single function call.
-    
-    Used around a function, like::
-
-        @profile_decorator(options...)
-        def ...
-
-    All calls to the function will be profiled.  The options are
-    all keywords, and are:
-
-        log_file:
-            The filename to log to (or ``'stdout'`` or ``'stderr'``).
-            Default: stderr.
-        display_limit:
-            Only show the top N items, default: 20.
-        sort_stats:
-            A list of string-attributes to sort on.  Default
-            ``('time', 'calls')``.
-        strip_dirs:
-            Strip directories/module names from files?  Default True.
-        add_info:
-            If given, this info will be added to the report (for your
-            own tracking).  Default: none.
-        log_filename:
-            The temporary filename to log profiling data to.  Default;
-            ``./profile_data.log.tmp``
-        no_profile:
-            If true, then don't actually profile anything.  Useful for
-            conditional profiling.
-    """
-
-    if options.get('no_profile'):
-        def decorator(func):
-            return func
-        return decorator
-    def decorator(func):
-        def replacement(*args, **kw):
-            return DecoratedProfile(func, **options)(*args, **kw)
-        return replacement
-    return decorator
-
-class DecoratedProfile(object):
-
-    lock = threading.Lock()
-
-    def __init__(self, func, **options):
-        self.func = func
-        self.options = options
-
-    def __call__(self, *args, **kw):
-        self.lock.acquire()
-        try:
-            return self.profile(self.func, *args, **kw)
-        finally:
-            self.lock.release()
-
-    def profile(self, func, *args, **kw):
-        ops = self.options
-        prof_filename = ops.get('log_filename', 'profile_data.log.tmp')
-        prof = hotshot.Profile(prof_filename)
-        prof.addinfo('Function Call',
-                     self.format_function(func, *args, **kw))
-        if ops.get('add_info'):
-            prof.addinfo('Extra info', ops['add_info'])
-        exc_info = None
-        try:
-            start_time = time.time()
-            try:
-                result = prof.runcall(func, *args, **kw)
-            except:
-                exc_info = sys.exc_info()
-            end_time = time.time()
-        finally:
-            prof.close()
-        stats = hotshot.stats.load(prof_filename)
-        os.unlink(prof_filename)
-        if ops.get('strip_dirs', True):
-            stats.strip_dirs()
-        stats.sort_stats(*ops.get('sort_stats', ('time', 'calls')))
-        display_limit = ops.get('display_limit', 20)
-        output = capture_output(stats.print_stats, display_limit)
-        output_callers = capture_output(
-            stats.print_callers, display_limit)
-        output_file = ops.get('log_file')
-        if output_file in (None, 'stderr'):
-            f = sys.stderr
-        elif output_file in ('-', 'stdout'):
-            f = sys.stdout
-        else:
-            f = open(output_file, 'a')
-            f.write('\n%s\n' % ('-'*60))
-            f.write('Date: %s\n' % time.strftime('%c'))
-        f.write('Function call: %s\n'
-                % self.format_function(func, *args, **kw))
-        f.write('Wall time: %0.2f seconds\n'
-                % (end_time - start_time))
-        f.write(output)
-        f.write(output_callers)
-        if output_file not in (None, '-', 'stdout', 'stderr'):
-            f.close()
-        if exc_info:
-            # We captured an exception earlier, now we re-raise it
-            raise exc_info[0], exc_info[1], exc_info[2]
-        return result
-        
-    def format_function(self, func, *args, **kw):
-        args = map(repr, args)
-        args.extend(
-            ['%s=%r' % (k, v) for k, v in kw.items()])
-        return '%s(%s)' % (func.__name__, ', '.join(args))
-            
-            
-def make_profile_middleware(
-    app, global_conf,
-    log_filename='profile.log.tmp',
-    limit=40):
-    """
-    Wrap the application in a component that will profile each
-    request.  The profiling data is then appended to the output
-    of each page.
-
-    Note that this serializes all requests (i.e., removing
-    concurrency).  Therefore never use this in production.
-    """
-    limit = int(limit)
-    return ProfileMiddleware(
-        app, log_filename=log_filename, limit=limit)
diff --git a/lib/paste/debug/testserver.py b/lib/paste/debug/testserver.py
@@ -1,93 +0,0 @@
-# (c) 2005 Clark C. Evans
-# This module is part of the Python Paste Project and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-# This code was written with funding by http://prometheusresearch.com
-"""
-WSGI Test Server
-
-This builds upon paste.util.baseserver to customize it for regressions
-where using raw_interactive won't do.
-
-
-"""
-import time
-from paste.httpserver import *
-
-class WSGIRegressionServer(WSGIServer):
-    """
-    A threaded WSGIServer for use in regression testing.  To use this
-    module, call serve(application, regression=True), and then call
-    server.accept() to let it handle one request.  When finished, use
-    server.stop() to shutdown the server. Note that all pending requests
-    are processed before the server shuts down.
-    """
-    defaulttimeout = 10
-    def __init__ (self, *args, **kwargs):
-        WSGIServer.__init__(self, *args, **kwargs)
-        self.stopping = []
-        self.pending = []
-        self.timeout = self.defaulttimeout
-        # this is a local connection, be quick
-        self.socket.settimeout(2) 
-    def serve_forever(self):
-        from threading import Thread
-        thread = Thread(target=self.serve_pending)
-        thread.start()
-    def reset_expires(self):
-        if self.timeout:
-            self.expires = time.time() + self.timeout
-    def close_request(self, *args, **kwargs):
-        WSGIServer.close_request(self, *args, **kwargs)
-        self.pending.pop()
-        self.reset_expires()
-    def serve_pending(self):
-        self.reset_expires()
-        while not self.stopping or self.pending:
-            now = time.time()
-            if now > self.expires and self.timeout:
-                # note regression test doesn't handle exceptions in
-                # threads very well; so we just print and exit
-                print "\nWARNING: WSGIRegressionServer timeout exceeded\n"
-                break
-            if self.pending:
-                self.handle_request()
-            time.sleep(.1)
-    def stop(self):
-        """ stop the server (called from tester's thread) """
-        self.stopping.append(True)
-    def accept(self, count = 1):
-        """ accept another request (called from tester's thread) """
-        assert not self.stopping
-        [self.pending.append(True) for x in range(count)]
-
-def serve(application, host=None, port=None, handler=None):
-    server = WSGIRegressionServer(application, host, port, handler)
-    print "serving on %s:%s" % server.server_address
-    server.serve_forever()
-    return server
-
-if __name__ == '__main__':
-    import urllib
-    from paste.wsgilib import dump_environ
-    server = serve(dump_environ)
-    baseuri = ("http://%s:%s" % server.server_address)
-
-    def fetch(path):
-        # tell the server to humor exactly one more request
-        server.accept(1)
-        # not needed; but this is what you do if the server 
-        # may not respond in a resonable time period
-        import socket
-        socket.setdefaulttimeout(5)
-        # build a uri, fetch and return
-        return urllib.urlopen(baseuri + path).read()
-      
-    assert "PATH_INFO: /foo" in fetch("/foo")
-    assert "PATH_INFO: /womble" in fetch("/womble")
-
-    # ok, let's make one more final request...
-    server.accept(1)
-    # and then schedule a stop()
-    server.stop()
-    # and then... fetch it...
-    urllib.urlopen(baseuri)
diff --git a/lib/paste/debug/watchthreads.py b/lib/paste/debug/watchthreads.py
@@ -1,347 +0,0 @@
-"""
-Watches the key ``paste.httpserver.thread_pool`` to see how many
-threads there are and report on any wedged threads.
-"""
-import sys
-import cgi
-import time
-import traceback
-from cStringIO import StringIO
-from thread import get_ident
-from paste import httpexceptions
-from paste.request import construct_url, parse_formvars
-from paste.util.template import HTMLTemplate, bunch
-
-page_template = HTMLTemplate('''
-<html>
- <head>
-  <style type="text/css">
-   body {
-     font-family: sans-serif;
-   }
-   table.environ tr td {
-     border-bottom: #bbb 1px solid;
-   }
-   table.environ tr td.bottom {
-     border-bottom: none;
-   }
-   table.thread {
-     border: 1px solid #000;
-     margin-bottom: 1em;
-   }
-   table.thread tr td {
-     border-bottom: #999 1px solid;
-     padding-right: 1em;
-   }
-   table.thread tr td.bottom {
-     border-bottom: none;
-   }
-   table.thread tr.this_thread td {
-     background-color: #006;
-     color: #fff;
-   }
-   a.button {
-     background-color: #ddd;
-     border: #aaa outset 2px;
-     text-decoration: none;
-     margin-top: 10px;
-     font-size: 80%;
-     color: #000;
-   }
-   a.button:hover {
-     background-color: #eee;
-     border: #bbb outset 2px;
-   }
-   a.button:active {
-     border: #bbb inset 2px;
-   }
-  </style>
-  <title>{{title}}</title>
- </head>
- <body>
-  <h1>{{title}}</h1>
-  {{if kill_thread_id}}
-  <div style="background-color: #060; color: #fff;
-              border: 2px solid #000;">
-  Thread {{kill_thread_id}} killed
-  </div>
-  {{endif}}
-  <div>Pool size: {{nworkers}}
-       {{if actual_workers > nworkers}}
-         + {{actual_workers-nworkers}} extra
-       {{endif}}
-       ({{nworkers_used}} used including current request)<br>
-       idle: {{len(track_threads["idle"])}},
-       busy: {{len(track_threads["busy"])}},
-       hung: {{len(track_threads["hung"])}},
-       dying: {{len(track_threads["dying"])}},
-       zombie: {{len(track_threads["zombie"])}}</div>
-
-{{for thread in threads}}
-
-<table class="thread">
- <tr {{if thread.thread_id == this_thread_id}}class="this_thread"{{endif}}>
-  <td>
-   <b>Thread</b>
-   {{if thread.thread_id == this_thread_id}}
-   (<i>this</i> request)
-   {{endif}}</td>
-  <td>
-   <b>{{thread.thread_id}}
-    {{if allow_kill}}
-    <form action="{{script_name}}/kill" method="POST"
-          style="display: inline">
-      <input type="hidden" name="thread_id" value="{{thread.thread_id}}">
-      <input type="submit" value="kill">
-    </form>
-    {{endif}}
-   </b>
-  </td>
- </tr>
- <tr>
-  <td>Time processing request</td>
-  <td>{{thread.time_html|html}}</td>
- </tr>
- <tr>
-  <td>URI</td>
-  <td>{{if thread.uri == 'unknown'}}
-      unknown
-      {{else}}<a href="{{thread.uri}}">{{thread.uri_short}}</a>
-      {{endif}}
-  </td>
- <tr>
-  <td colspan="2" class="bottom">
-   <a href="#" class="button" style="width: 9em; display: block"
-      onclick="
-        var el = document.getElementById('environ-{{thread.thread_id}}');
-        if (el.style.display) {
-            el.style.display = '';
-            this.innerHTML = \'&#9662; Hide environ\';
-        } else {
-            el.style.display = 'none';
-            this.innerHTML = \'&#9656; Show environ\';
-        }
-        return false
-      ">&#9656; Show environ</a>
-   
-   <div id="environ-{{thread.thread_id}}" style="display: none">
-    {{if thread.environ:}}
-    <table class="environ">
-     {{for loop, item in looper(sorted(thread.environ.items()))}}
-     {{py:key, value=item}}
-     <tr>
-      <td {{if loop.last}}class="bottom"{{endif}}>{{key}}</td>
-      <td {{if loop.last}}class="bottom"{{endif}}>{{value}}</td>
-     </tr>
-     {{endfor}}
-    </table>
-    {{else}}
-    Thread is in process of starting
-    {{endif}}
-   </div>
-
-   {{if thread.traceback}}
-   <a href="#" class="button" style="width: 9em; display: block"
-      onclick="
-        var el = document.getElementById('traceback-{{thread.thread_id}}');
-        if (el.style.display) {
-            el.style.display = '';
-            this.innerHTML = \'&#9662; Hide traceback\';
-        } else {
-            el.style.display = 'none';
-            this.innerHTML = \'&#9656; Show traceback\';
-        }
-        return false
-      ">&#9656; Show traceback</a>
-
-    <div id="traceback-{{thread.thread_id}}" style="display: none">
-      <pre class="traceback">{{thread.traceback}}</pre>
-    </div>
-    {{endif}}
-
-  </td>
- </tr>
-</table>
-
-{{endfor}}
-
- </body>
-</html>
-''', name='watchthreads.page_template')
-
-class WatchThreads(object):
-
-    """
-    Application that watches the threads in ``paste.httpserver``,
-    showing the length each thread has been working on a request.
-
-    If allow_kill is true, then you can kill errant threads through
-    this application.
-
-    This application can expose private information (specifically in
-    the environment, like cookies), so it should be protected.
-    """
-
-    def __init__(self, allow_kill=False):
-        self.allow_kill = allow_kill
-
-    def __call__(self, environ, start_response):
-        if 'paste.httpserver.thread_pool' not in environ:
-            start_response('403 Forbidden', [('Content-type', 'text/plain')])
-            return ['You must use the threaded Paste HTTP server to use this application']
-        if environ.get('PATH_INFO') == '/kill':
-            return self.kill(environ, start_response)
-        else:
-            return self.show(environ, start_response)
-
-    def show(self, environ, start_response):
-        start_response('200 OK', [('Content-type', 'text/html')])
-        form = parse_formvars(environ)
-        if form.get('kill'):
-            kill_thread_id = form['kill']
-        else:
-            kill_thread_id = None
-        thread_pool = environ['paste.httpserver.thread_pool']
-        nworkers = thread_pool.nworkers
-        now = time.time()
-
-
-        workers = thread_pool.worker_tracker.items()
-        workers.sort(key=lambda v: v[1][0])
-        threads = []
-        for thread_id, (time_started, worker_environ) in workers:
-            thread = bunch()
-            threads.append(thread)
-            if worker_environ:
-                thread.uri = construct_url(worker_environ)
-            else:
-                thread.uri = 'unknown'
-            thread.thread_id = thread_id
-            thread.time_html = format_time(now-time_started)
-            thread.uri_short = shorten(thread.uri)
-            thread.environ = worker_environ
-            thread.traceback = traceback_thread(thread_id)
-            
-        page = page_template.substitute(
-            title="Thread Pool Worker Tracker",
-            nworkers=nworkers,
-            actual_workers=len(thread_pool.workers),
-            nworkers_used=len(workers),
-            script_name=environ['SCRIPT_NAME'],
-            kill_thread_id=kill_thread_id,
-            allow_kill=self.allow_kill,
-            threads=threads,
-            this_thread_id=get_ident(),
-            track_threads=thread_pool.track_threads())
-
-        return [page]
-
-    def kill(self, environ, start_response):
-        if not self.allow_kill:
-            exc = httpexceptions.HTTPForbidden(
-                'Killing threads has not been enabled.  Shame on you '
-                'for trying!')
-            return exc(environ, start_response)
-        vars = parse_formvars(environ)
-        thread_id = int(vars['thread_id'])
-        thread_pool = environ['paste.httpserver.thread_pool']
-        if thread_id not in thread_pool.worker_tracker:
-            exc = httpexceptions.PreconditionFailed(
-                'You tried to kill thread %s, but it is not working on '
-                'any requests' % thread_id)
-            return exc(environ, start_response)
-        thread_pool.kill_worker(thread_id)
-        script_name = environ['SCRIPT_NAME'] or '/'
-        exc = httpexceptions.HTTPFound(
-            headers=[('Location', script_name+'?kill=%s' % thread_id)])
-        return exc(environ, start_response)
-        
-def traceback_thread(thread_id):
-    """
-    Returns a plain-text traceback of the given thread, or None if it
-    can't get a traceback.
-    """
-    if not hasattr(sys, '_current_frames'):
-        # Only 2.5 has support for this, with this special function
-        return None
-    frames = sys._current_frames()
-    if not thread_id in frames:
-        return None
-    frame = frames[thread_id]
-    out = StringIO()
-    traceback.print_stack(frame, file=out)
-    return out.getvalue()
-
-hide_keys = ['paste.httpserver.thread_pool']
-
-def format_environ(environ):
-    if environ is None:
-        return environ_template.substitute(
-            key='---',
-            value='No environment registered for this thread yet')
-    environ_rows = []
-    for key, value in sorted(environ.items()):
-        if key in hide_keys:
-            continue
-        try:
-            if key.upper() != key:
-                value = repr(value)
-            environ_rows.append(
-                environ_template.substitute(
-                key=cgi.escape(str(key)),
-                value=cgi.escape(str(value))))
-        except Exception, e:
-            environ_rows.append(
-                environ_template.substitute(
-                key=cgi.escape(str(key)),
-                value='Error in <code>repr()</code>: %s' % e))
-    return ''.join(environ_rows)
-    
-def format_time(time_length):
-    if time_length >= 60*60:
-        # More than an hour
-        time_string = '%i:%02i:%02i' % (int(time_length/60/60),
-                                        int(time_length/60) % 60,
-                                        time_length % 60)
-    elif time_length >= 120:
-        time_string = '%i:%02i' % (int(time_length/60),
-                                   time_length % 60)
-    elif time_length > 60:
-        time_string = '%i sec' % time_length
-    elif time_length > 1:
-        time_string = '%0.1f sec' % time_length
-    else:
-        time_string = '%0.2f sec' % time_length
-    if time_length < 5:
-        return time_string
-    elif time_length < 120:
-        return '<span style="color: #900">%s</span>' % time_string
-    else:
-        return '<span style="background-color: #600; color: #fff">%s</span>' % time_string
-
-def shorten(s):
-    if len(s) > 60:
-        return s[:40]+'...'+s[-10:]
-    else:
-        return s
-
-def make_watch_threads(global_conf, allow_kill=False):
-    from paste.deploy.converters import asbool
-    return WatchThreads(allow_kill=asbool(allow_kill))
-make_watch_threads.__doc__ = WatchThreads.__doc__
-
-def make_bad_app(global_conf, pause=0):
-    pause = int(pause)
-    def bad_app(environ, start_response):
-        import thread
-        if pause:
-            time.sleep(pause)
-        else:
-            count = 0
-            while 1:
-                print "I'm alive %s (%s)" % (count, thread.get_ident())
-                time.sleep(10)
-                count += 1
-        start_response('200 OK', [('content-type', 'text/plain')])
-        return ['OK, paused %s seconds' % pause]
-    return bad_app
diff --git a/lib/paste/debug/wdg_validate.py b/lib/paste/debug/wdg_validate.py
@@ -1,117 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-Middleware that tests the validity of all generated HTML using the
-`WDG HTML Validator <http://www.htmlhelp.com/tools/validator/>`_
-"""
-
-from cStringIO import StringIO
-try:
-    import subprocess
-except ImportError:
-    from paste.util import subprocess24 as subprocess
-from paste import wsgilib
-import re
-import cgi
-
-__all__ = ['WDGValidateMiddleware']
-
-class WDGValidateMiddleware(object):
-
-    """
-    Middleware that checks HTML and appends messages about the validity of
-    the HTML.  Uses: http://www.htmlhelp.com/tools/validator/ -- interacts
-    with the command line client.  Use the configuration ``wdg_path`` to
-    override the path (default: looks for ``validate`` in $PATH).
-
-    To install, in your web context's __init__.py::
-
-        def urlparser_wrap(environ, start_response, app):
-            return wdg_validate.WDGValidateMiddleware(app)(
-                environ, start_response)
-
-    Or in your configuration::
-
-        middleware.append('paste.wdg_validate.WDGValidateMiddleware')
-    """
-
-    _end_body_regex = re.compile(r'</body>', re.I)
-
-    def __init__(self, app, global_conf=None, wdg_path='validate'):
-        self.app = app
-        self.wdg_path = wdg_path
-
-    def __call__(self, environ, start_response):
-        output = StringIO()
-        response = []
-
-        def writer_start_response(status, headers, exc_info=None):
-            response.extend((status, headers))
-            start_response(status, headers, exc_info)
-            return output.write
-
-        app_iter = self.app(environ, writer_start_response)
-        try:
-            for s in app_iter:
-                output.write(s)
-        finally:
-            if hasattr(app_iter, 'close'):
-                app_iter.close()
-        page = output.getvalue()
-        status, headers = response
-        v = wsgilib.header_value(headers, 'content-type') or ''
-        if (not v.startswith('text/html')
-            and not v.startswith('text/xhtml')
-            and not v.startswith('application/xhtml')):
-            # Can't validate
-            # @@: Should validate CSS too... but using what?
-            return [page]
-        ops = []
-        if v.startswith('text/xhtml+xml'):
-            ops.append('--xml')
-        # @@: Should capture encoding too
-        html_errors = self.call_wdg_validate(
-            self.wdg_path, ops, page)
-        if not html_errors:
-            return [page]
-        return self.add_error(page, html_errors)
-    
-    def call_wdg_validate(self, wdg_path, ops, page):
-        if subprocess is None:
-            raise ValueError(
-                "This middleware requires the subprocess module from "
-                "Python 2.4")
-        proc = subprocess.Popen([wdg_path] + ops,
-                                shell=False,
-                                close_fds=True,
-                                stdout=subprocess.PIPE,
-                                stdin=subprocess.PIPE,
-                                stderr=subprocess.STDOUT)
-        stdout = proc.communicate(page)[0]
-        proc.wait()
-        return stdout
-            
-    def add_error(self, html_page, html_errors):
-        add_text = ('<pre style="background-color: #ffd; color: #600; '
-                    'border: 1px solid #000;">%s</pre>'
-                    % cgi.escape(html_errors))
-        match = self._end_body_regex.search(html_page)
-        if match:
-            return [html_page[:match.start()]
-                    + add_text
-                    + html_page[match.end():]]
-        else:
-            return [html_page + add_text]
-
-def make_wdg_validate_middleware(
-    app, global_conf, wdg_path='validate'):
-    """
-    Wraps the application in the WDG validator from
-    http://www.htmlhelp.com/tools/validator/
-
-    Validation errors are appended to the text of each page.
-    You can configure this by giving the path to the validate
-    executable (by default picked up from $PATH)
-    """
-    return WDGValidateMiddleware(
-        app, global_conf, wdg_path=wdg_path)
diff --git a/lib/paste/errordocument.py b/lib/paste/errordocument.py
@@ -1,372 +0,0 @@
-# (c) 2005-2006 James Gardner <james@pythonweb.org>
-# This module is part of the Python Paste Project and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-"""
-Middleware to display error documents for certain status codes
-
-The middleware in this module can be used to intercept responses with
-specified status codes and internally forward the request to an appropriate
-URL where the content can be displayed to the user as an error document.
-"""
-
-import warnings
-from urlparse import urlparse
-from paste.recursive import ForwardRequestException, RecursiveMiddleware
-from paste.util import converters
-from paste.response import replace_header
-
-def forward(app, codes):
-    """
-    Intercepts a response with a particular status code and returns the 
-    content from a specified URL instead.
-    
-    The arguments are:
-    
-    ``app``
-        The WSGI application or middleware chain.
-
-    ``codes``
-        A dictionary of integer status codes and the URL to be displayed
-        if the response uses that code.
-        
-    For example, you might want to create a static file to display a 
-    "File Not Found" message at the URL ``/error404.html`` and then use
-    ``forward`` middleware to catch all 404 status codes and display the page
-    you created. In this example ``app`` is your exisiting WSGI 
-    applicaiton::
-
-        from paste.errordocument import forward
-        app = forward(app, codes={404:'/error404.html'})
-
-    """
-    for code in codes:
-        if not isinstance(code, int):
-            raise TypeError('All status codes should be type int. '
-                '%s is not valid'%repr(code))
-                
-    def error_codes_mapper(code, message, environ, global_conf, codes):
-        if codes.has_key(code):
-            return codes[code]
-        else:
-            return None
-
-    #return _StatusBasedRedirect(app, error_codes_mapper, codes=codes)
-    return RecursiveMiddleware(
-        StatusBasedForward(
-            app, 
-            error_codes_mapper, 
-            codes=codes,
-        )
-    )
-
-class StatusKeeper(object):
-    def __init__(self, app, status, url, headers):
-        self.app = app
-        self.status = status
-        self.url = url
-        self.headers = headers
-
-    def __call__(self, environ, start_response):
-        def keep_status_start_response(status, headers, exc_info=None):
-            for header, value in headers:
-                if header.lower() == 'set-cookie':
-                    self.headers.append((header, value))
-                else:
-                    replace_header(self.headers, header, value)
-            return start_response(self.status, self.headers, exc_info)
-        parts = self.url.split('?')
-        environ['PATH_INFO'] = parts[0]
-        if len(parts) > 1:
-            environ['QUERY_STRING'] = parts[1]
-        else:
-            environ['QUERY_STRING'] = ''
-        #raise Exception(self.url, self.status)
-        return self.app(environ, keep_status_start_response)
-        
-class StatusBasedForward(object):
-    """
-    Middleware that lets you test a response against a custom mapper object to
-    programatically determine whether to internally forward to another URL and
-    if so, which URL to forward to.
-    
-    If you don't need the full power of this middleware you might choose to use
-    the simpler ``forward`` middleware instead.
-
-    The arguments are:
-    
-    ``app``
-        The WSGI application or middleware chain.
-        
-    ``mapper`` 
-        A callable that takes a status code as the
-        first parameter, a message as the second, and accepts optional environ,
-        global_conf and named argments afterwards. It should return a
-        URL to forward to or ``None`` if the code is not to be intercepted.
-
-    ``global_conf``
-        Optional default configuration from your config file. If ``debug`` is
-        set to ``true`` a message will be written to ``wsgi.errors`` on each
-        internal forward stating the URL forwarded to.
-    
-    ``**params`` 
-        Optional, any other configuration and extra arguments you wish to 
-        pass which will in turn be passed back to the custom mapper object.
-
-    Here is an example where a ``404 File Not Found`` status response would be
-    redirected to the URL ``/error?code=404&message=File%20Not%20Found``. This 
-    could be useful for passing the status code and message into another 
-    application to display an error document:
-    
-    .. code-block:: python
-    
-        from paste.errordocument import StatusBasedForward
-        from paste.recursive import RecursiveMiddleware
-        from urllib import urlencode
-        
-        def error_mapper(code, message, environ, global_conf, kw)
-            if code in [404, 500]:
-                params = urlencode({'message':message, 'code':code})
-                url = '/error?'%(params)
-                return url
-            else:
-                return None
-    
-        app = RecursiveMiddleware(
-            StatusBasedForward(app, mapper=error_mapper),
-        )
-
-    """
-
-    def __init__(self, app, mapper, global_conf=None, **params):
-        if global_conf is None:
-            global_conf = {}
-        # @@: global_conf shouldn't really come in here, only in a
-        # separate make_status_based_forward function
-        if global_conf:
-            self.debug = converters.asbool(global_conf.get('debug', False))
-        else:
-            self.debug = False
-        self.application = app
-        self.mapper = mapper
-        self.global_conf = global_conf
-        self.params = params
-
-    def __call__(self, environ, start_response):
-        url = []
-        
-        def change_response(status, headers, exc_info=None):
-            status_code = status.split(' ')
-            try:
-                code = int(status_code[0])
-            except (ValueError, TypeError):
-                raise Exception(
-                    'StatusBasedForward middleware '
-                    'received an invalid status code %s'%repr(status_code[0])
-                )
-            message = ' '.join(status_code[1:])
-            new_url = self.mapper(
-                code, 
-                message, 
-                environ, 
-                self.global_conf, 
-                **self.params
-            )
-            if not (new_url == None or isinstance(new_url, str)):
-                raise TypeError(
-                    'Expected the url to internally '
-                    'redirect to in the StatusBasedForward mapper'
-                    'to be a string or None, not %s'%repr(new_url)
-                )
-            if new_url:
-                url.append([new_url, status, headers])
-            else:
-                return start_response(status, headers, exc_info)
-
-        app_iter = self.application(environ, change_response)
-        if url:
-            if hasattr(app_iter, 'close'):
-                app_iter.close()
-
-            def factory(app):
-                return StatusKeeper(app, status=url[0][1], url=url[0][0],
-                                    headers=url[0][2])
-            raise ForwardRequestException(factory=factory)
-        else:
-            return app_iter
-
-def make_errordocument(app, global_conf, **kw):
-    """
-    Paste Deploy entry point to create a error document wrapper. 
-    
-    Use like::
-
-        [filter-app:main]
-        use = egg:Paste#errordocument
-        next = real-app
-        500 = /lib/msg/500.html
-        404 = /lib/msg/404.html
-    """
-    map = {}
-    for status, redir_loc in kw.items():
-        try:
-            status = int(status)
-        except ValueError:
-            raise ValueError('Bad status code: %r' % status)
-        map[status] = redir_loc
-    forwarder = forward(app, map)
-    return forwarder
-
-__pudge_all__ = [
-    'forward',
-    'make_errordocument',
-    'empty_error',
-    'make_empty_error',
-    'StatusBasedForward',
-]
-
-
-###############################################################################
-## Deprecated
-###############################################################################
-
-def custom_forward(app, mapper, global_conf=None, **kw):
-    """
-    Deprectated; use StatusBasedForward instead.
-    """
-    warnings.warn(
-        "errordocuments.custom_forward has been deprecated; please "
-        "use errordocuments.StatusBasedForward",
-        DeprecationWarning, 2)
-    if global_conf is None:
-        global_conf = {}
-    return _StatusBasedRedirect(app, mapper, global_conf, **kw)
-
-class _StatusBasedRedirect(object):
-    """
-    Deprectated; use StatusBasedForward instead.
-    """
-    def __init__(self, app, mapper, global_conf=None, **kw):
-
-        warnings.warn(
-            "errordocuments._StatusBasedRedirect has been deprecated; please "
-            "use errordocuments.StatusBasedForward",
-            DeprecationWarning, 2)
-
-        if global_conf is None:
-            global_conf = {}
-        self.application = app
-        self.mapper = mapper
-        self.global_conf = global_conf
-        self.kw = kw
-        self.fallback_template = """
-            <html>
-            <head>
-            <title>Error %(code)s</title>
-            </html>
-            <body>
-            <h1>Error %(code)s</h1>
-            <p>%(message)s</p>
-            <hr>
-            <p>
-                Additionally an error occurred trying to produce an 
-                error document.  A description of the error was logged
-                to <tt>wsgi.errors</tt>.
-            </p>
-            </body>
-            </html>                
-        """
-        
-    def __call__(self, environ, start_response):
-        url = []
-        code_message = []
-        try:
-            def change_response(status, headers, exc_info=None):
-                new_url = None
-                parts = status.split(' ')
-                try:
-                    code = int(parts[0])
-                except ValueError, TypeError:
-                    raise Exception(
-                        '_StatusBasedRedirect middleware '
-                        'received an invalid status code %s'%repr(parts[0])
-                    )
-                message = ' '.join(parts[1:])
-                new_url = self.mapper(
-                    code, 
-                    message, 
-                    environ, 
-                    self.global_conf, 
-                    self.kw
-                )
-                if not (new_url == None or isinstance(new_url, str)):
-                    raise TypeError(
-                        'Expected the url to internally '
-                        'redirect to in the _StatusBasedRedirect error_mapper'
-                        'to be a string or None, not %s'%repr(new_url)
-                    )
-                if new_url:
-                    url.append(new_url)
-                code_message.append([code, message])
-                return start_response(status, headers, exc_info)
-            app_iter = self.application(environ, change_response)
-        except:
-            try:
-                import sys
-                error = str(sys.exc_info()[1])
-            except:
-                error = ''
-            try:
-                code, message = code_message[0]
-            except:
-                code, message = ['', '']
-            environ['wsgi.errors'].write(
-                'Error occurred in _StatusBasedRedirect '
-                'intercepting the response: '+str(error)
-            )
-            return [self.fallback_template
-                    % {'message': message, 'code': code}]
-        else:
-            if url:
-                url_ = url[0]
-                new_environ = {}
-                for k, v in environ.items():
-                    if k != 'QUERY_STRING':
-                        new_environ['QUERY_STRING'] = urlparse(url_)[4]
-                    else:
-                        new_environ[k] = v
-                class InvalidForward(Exception):
-                    pass
-                def eat_start_response(status, headers, exc_info=None):
-                    """
-                    We don't want start_response to do anything since it
-                    has already been called
-                    """
-                    if status[:3] != '200':
-                        raise InvalidForward(
-                            "The URL %s to internally forward "
-                            "to in order to create an error document did not "
-                            "return a '200' status code." % url_
-                        )
-                forward = environ['paste.recursive.forward']
-                old_start_response = forward.start_response
-                forward.start_response = eat_start_response
-                try:
-                    app_iter = forward(url_, new_environ)
-                except InvalidForward, e:
-                    code, message = code_message[0]
-                    environ['wsgi.errors'].write(
-                        'Error occurred in '
-                        '_StatusBasedRedirect redirecting '
-                        'to new URL: '+str(url[0])
-                    )
-                    return [
-                        self.fallback_template%{
-                            'message':message,
-                            'code':code,
-                        }
-                    ]
-                else:
-                    forward.start_response = old_start_response
-                    return app_iter
-            else:
-                return app_iter
diff --git a/lib/paste/evalexception/__init__.py b/lib/paste/evalexception/__init__.py
@@ -1,7 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-An exception handler for interactive debugging
-"""
-from paste.evalexception.middleware import EvalException
-
diff --git a/lib/paste/evalexception/evalcontext.py b/lib/paste/evalexception/evalcontext.py
@@ -1,68 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-from cStringIO import StringIO
-import traceback
-import threading
-import pdb
-import sys
-
-exec_lock = threading.Lock()
-
-class EvalContext(object):
-
-    """
-    Class that represents a interactive interface.  It has its own
-    namespace.  Use eval_context.exec_expr(expr) to run commands; the
-    output of those commands is returned, as are print statements.
-
-    This is essentially what doctest does, and is taken directly from
-    doctest.
-    """
-
-    def __init__(self, namespace, globs):
-        self.namespace = namespace
-        self.globs = globs
-
-    def exec_expr(self, s):
-        out = StringIO()
-        exec_lock.acquire()
-        save_stdout = sys.stdout
-        try:
-            debugger = _OutputRedirectingPdb(save_stdout)
-            debugger.reset()
-            pdb.set_trace = debugger.set_trace
-            sys.stdout = out
-            try:
-                code = compile(s, '<web>', "single", 0, 1)
-                exec code in self.namespace, self.globs
-                debugger.set_continue()
-            except KeyboardInterrupt:
-                raise
-            except:
-                traceback.print_exc(file=out)
-                debugger.set_continue()
-        finally:
-            sys.stdout = save_stdout
-            exec_lock.release()
-        return out.getvalue()
-
-# From doctest
-class _OutputRedirectingPdb(pdb.Pdb):
-    """
-    A specialized version of the python debugger that redirects stdout
-    to a given stream when interacting with the user.  Stdout is *not*
-    redirected when traced code is executed.
-    """
-    def __init__(self, out):
-        self.__out = out
-        pdb.Pdb.__init__(self)
-
-    def trace_dispatch(self, *args):
-        # Redirect stdout to the given stream.
-        save_stdout = sys.stdout
-        sys.stdout = self.__out
-        # Call Pdb's trace dispatch method.
-        try:
-            return pdb.Pdb.trace_dispatch(self, *args)
-        finally:
-            sys.stdout = save_stdout
diff --git a/lib/paste/evalexception/media/debug.js b/lib/paste/evalexception/media/debug.js
@@ -1,161 +0,0 @@
-function showFrame(anchor) {
-    var tbid = anchor.getAttribute('tbid');
-    var expanded = anchor.expanded;
-    if (expanded) {
-        MochiKit.DOM.hideElement(anchor.expandedElement);
-        anchor.expanded = false;
-        _swapImage(anchor);
-        return false;
-    }
-    anchor.expanded = true;
-    if (anchor.expandedElement) {
-        MochiKit.DOM.showElement(anchor.expandedElement);
-        _swapImage(anchor);
-        $('debug_input_'+tbid).focus();
-        return false;
-    }
-    var url = debug_base
-        + '/show_frame?tbid=' + tbid
-        + '&debugcount=' + debug_count;
-    var d = MochiKit.Async.doSimpleXMLHttpRequest(url);
-    d.addCallbacks(function (data) {
-        var el = MochiKit.DOM.DIV({});
-        anchor.parentNode.insertBefore(el, anchor.nextSibling);
-        el.innerHTML = data.responseText;
-        anchor.expandedElement = el;
-        _swapImage(anchor);
-        $('debug_input_'+tbid).focus();
-    }, function (error) {
-        showError(error.req.responseText);
-    });
-    return false;
-}
-
-function _swapImage(anchor) {
-    var el = anchor.getElementsByTagName('IMG')[0];
-    if (anchor.expanded) {
-        var img = 'minus.jpg';
-    } else {
-        var img = 'plus.jpg';
-    }
-    el.src = debug_base + '/media/' + img;
-}
-
-function submitInput(button, tbid) {
-    var input = $(button.getAttribute('input-from'));
-    var output = $(button.getAttribute('output-to'));
-    var url = debug_base
-        + '/exec_input';
-    var history = input.form.history;
-    input.historyPosition = 0;
-    if (! history) {
-        history = input.form.history = [];
-    }
-    history.push(input.value);
-    var vars = {
-        tbid: tbid,
-        debugcount: debug_count,
-        input: input.value
-    };
-    MochiKit.DOM.showElement(output);
-    var d = MochiKit.Async.doSimpleXMLHttpRequest(url, vars);
-    d.addCallbacks(function (data) {
-        var result = data.responseText;
-        output.innerHTML += result;
-        input.value = '';
-        input.focus();
-    }, function (error) {
-        showError(error.req.responseText);
-    });
-    return false;
-}
-
-function showError(msg) {
-    var el = $('error-container');
-    if (el.innerHTML) {
-        el.innerHTML += '<hr noshade>\n' + msg;
-    } else {
-        el.innerHTML = msg;
-    }
-    MochiKit.DOM.showElement('error-area');
-}
-
-function clearError() {
-    var el = $('error-container');
-    el.innerHTML = '';
-    MochiKit.DOM.hideElement('error-area');
-}
-
-function expandInput(button) {
-    var input = button.form.elements.input;
-    stdops = {
-        name: 'input',
-        style: 'width: 100%',
-        autocomplete: 'off'
-    };
-    if (input.tagName == 'INPUT') {
-        var newEl = MochiKit.DOM.TEXTAREA(stdops);
-        var text = 'Contract';
-    } else {
-        stdops['type'] = 'text';
-        stdops['onkeypress'] = 'upArrow(this)';
-        var newEl = MochiKit.DOM.INPUT(stdops);
-        var text = 'Expand';
-    }
-    newEl.value = input.value;
-    newEl.id = input.id;
-    MochiKit.DOM.swapDOM(input, newEl);
-    newEl.focus();
-    button.value = text;
-    return false;
-}
-
-function upArrow(input, event) {
-    if (window.event) {
-        event = window.event;
-    }
-    if (event.keyCode != 38 && event.keyCode != 40) {
-        // not an up- or down-arrow
-        return true;
-    }
-    var dir = event.keyCode == 38 ? 1 : -1;
-    var history = input.form.history;
-    if (! history) {
-        history = input.form.history = [];
-    }
-    var pos = input.historyPosition || 0;
-    if (! pos && dir == -1) {
-        return true;
-    }
-    if (! pos && input.value) {
-        history.push(input.value);
-        pos = 1;
-    }
-    pos += dir;
-    if (history.length-pos < 0) {
-        pos = 1;
-    }
-    if (history.length-pos > history.length-1) {
-        input.value = '';
-        return true;
-    }
-    input.historyPosition = pos;
-    var line = history[history.length-pos];
-    input.value = line;
-}
-
-function expandLong(anchor) {
-    var span = anchor;
-    while (span) {
-        if (span.style && span.style.display == 'none') {
-            break;
-        }
-        span = span.nextSibling;
-    }
-    if (! span) {
-        return false;
-    }
-    MochiKit.DOM.showElement(span);
-    MochiKit.DOM.hideElement(anchor);
-    return false;
-}
diff --git a/lib/paste/evalexception/media/minus.jpg b/lib/paste/evalexception/media/minus.jpg
Binary files differ.
diff --git a/lib/paste/evalexception/media/plus.jpg b/lib/paste/evalexception/media/plus.jpg
Binary files differ.
diff --git a/lib/paste/evalexception/middleware.py b/lib/paste/evalexception/middleware.py
@@ -1,611 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-Exception-catching middleware that allows interactive debugging.
-
-This middleware catches all unexpected exceptions.  A normal
-traceback, like produced by
-``paste.exceptions.errormiddleware.ErrorMiddleware`` is given, plus
-controls to see local variables and evaluate expressions in a local
-context.
-
-This can only be used in single-process environments, because
-subsequent requests must go back to the same process that the
-exception originally occurred in.  Threaded or non-concurrent
-environments both work.
-
-This shouldn't be used in production in any way.  That would just be
-silly.
-
-If calling from an XMLHttpRequest call, if the GET variable ``_`` is
-given then it will make the response more compact (and less
-Javascripty), since if you use innerHTML it'll kill your browser.  You
-can look for the header X-Debug-URL in your 500 responses if you want
-to see the full debuggable traceback.  Also, this URL is printed to
-``wsgi.errors``, so you can open it up in another browser window.
-"""
-import sys
-import os
-import cgi
-import traceback
-from cStringIO import StringIO
-import pprint
-import itertools
-import time
-import re
-from paste.exceptions import errormiddleware, formatter, collector
-from paste import wsgilib
-from paste import urlparser
-from paste import httpexceptions
-from paste import registry
-from paste import request
-from paste import response
-import evalcontext
-
-limit = 200
-
-def html_quote(v):
-    """
-    Escape HTML characters, plus translate None to ''
-    """
-    if v is None:
-        return ''
-    return cgi.escape(str(v), 1)
-
-def preserve_whitespace(v, quote=True):
-    """
-    Quote a value for HTML, preserving whitespace (translating
-    newlines to ``<br>`` and multiple spaces to use ``&nbsp;``).
-
-    If ``quote`` is true, then the value will be HTML quoted first.
-    """
-    if quote:
-        v = html_quote(v)
-    v = v.replace('\n', '<br>\n')
-    v = re.sub(r'()(  +)', _repl_nbsp, v)
-    v = re.sub(r'(\n)( +)', _repl_nbsp, v)
-    v = re.sub(r'^()( +)', _repl_nbsp, v)
-    return '<code>%s</code>' % v
-
-def _repl_nbsp(match):
-    if len(match.group(2)) == 1:
-        return '&nbsp;'
-    return match.group(1) + '&nbsp;' * (len(match.group(2))-1) + ' '
-
-def simplecatcher(application):
-    """
-    A simple middleware that catches errors and turns them into simple
-    tracebacks.
-    """
-    def simplecatcher_app(environ, start_response):
-        try:
-            return application(environ, start_response)
-        except:
-            out = StringIO()
-            traceback.print_exc(file=out)
-            start_response('500 Server Error',
-                           [('content-type', 'text/html')],
-                           sys.exc_info())
-            res = out.getvalue()
-            return ['<h3>Error</h3><pre>%s</pre>'
-                    % html_quote(res)]
-    return simplecatcher_app
-
-def wsgiapp():
-    """
-    Turns a function or method into a WSGI application.
-    """
-    def decorator(func):
-        def wsgiapp_wrapper(*args):
-            # we get 3 args when this is a method, two when it is
-            # a function :(
-            if len(args) == 3:
-                environ = args[1]
-                start_response = args[2]
-                args = [args[0]]
-            else:
-                environ, start_response = args
-                args = []
-            def application(environ, start_response):
-                form = wsgilib.parse_formvars(environ,
-                                              include_get_vars=True)
-                headers = response.HeaderDict(
-                    {'content-type': 'text/html',
-                     'status': '200 OK'})
-                form['environ'] = environ
-                form['headers'] = headers
-                res = func(*args, **form.mixed())
-                status = headers.pop('status')
-                start_response(status, headers.headeritems())
-                return [res]
-            app = httpexceptions.make_middleware(application)
-            app = simplecatcher(app)
-            return app(environ, start_response)
-        wsgiapp_wrapper.exposed = True
-        return wsgiapp_wrapper
-    return decorator
-
-def get_debug_info(func):
-    """
-    A decorator (meant to be used under ``wsgiapp()``) that resolves
-    the ``debugcount`` variable to a ``DebugInfo`` object (or gives an
-    error if it can't be found).
-    """
-    def debug_info_replacement(self, **form):
-        try:
-            if 'debugcount' not in form:
-                raise ValueError('You must provide a debugcount parameter')
-            debugcount = form.pop('debugcount')
-            try:
-                debugcount = int(debugcount)
-            except ValueError:
-                raise ValueError('Bad value for debugcount')
-            if debugcount not in self.debug_infos:
-                raise ValueError(
-                    'Debug %s no longer found (maybe it has expired?)'
-                    % debugcount)
-            debug_info = self.debug_infos[debugcount]
-            return func(self, debug_info=debug_info, **form)
-        except ValueError, e:
-            form['headers']['status'] = '500 Server Error'
-            return '<html>There was an error: %s</html>' % html_quote(e)
-    return debug_info_replacement
-            
-debug_counter = itertools.count(int(time.time()))
-def get_debug_count(environ):
-    """
-    Return the unique debug count for the current request
-    """
-    if 'paste.evalexception.debug_count' in environ:
-        return environ['paste.evalexception.debug_count']
-    else:
-        environ['paste.evalexception.debug_count'] = next = debug_counter.next()
-        return next
-
-class EvalException(object):
-
-    def __init__(self, application, global_conf=None,
-                 xmlhttp_key=None):
-        self.application = application
-        self.debug_infos = {}
-        if xmlhttp_key is None:
-            if global_conf is None:
-                xmlhttp_key = '_'
-            else:
-                xmlhttp_key = global_conf.get('xmlhttp_key', '_')
-        self.xmlhttp_key = xmlhttp_key
-
-    def __call__(self, environ, start_response):
-        assert not environ['wsgi.multiprocess'], (
-            "The EvalException middleware is not usable in a "
-            "multi-process environment")
-        environ['paste.evalexception'] = self
-        if environ.get('PATH_INFO', '').startswith('/_debug/'):
-            return self.debug(environ, start_response)
-        else:
-            return self.respond(environ, start_response)
-
-    def debug(self, environ, start_response):
-        assert request.path_info_pop(environ) == '_debug'
-        next_part = request.path_info_pop(environ)
-        method = getattr(self, next_part, None)
-        if not method:
-            exc = httpexceptions.HTTPNotFound(
-                '%r not found when parsing %r'
-                % (next_part, wsgilib.construct_url(environ)))
-            return exc.wsgi_application(environ, start_response)
-        if not getattr(method, 'exposed', False):
-            exc = httpexceptions.HTTPForbidden(
-                '%r not allowed' % next_part)
-            return exc.wsgi_application(environ, start_response)
-        return method(environ, start_response)
-
-    def media(self, environ, start_response):
-        """
-        Static path where images and other files live
-        """
-        app = urlparser.StaticURLParser(
-            os.path.join(os.path.dirname(__file__), 'media'))
-        return app(environ, start_response)
-    media.exposed = True
-
-    def mochikit(self, environ, start_response):
-        """
-        Static path where MochiKit lives
-        """
-        app = urlparser.StaticURLParser(
-            os.path.join(os.path.dirname(__file__), 'mochikit'))
-        return app(environ, start_response)
-    mochikit.exposed = True
-
-    def summary(self, environ, start_response):
-        """
-        Returns a JSON-format summary of all the cached
-        exception reports
-        """
-        start_response('200 OK', [('Content-type', 'text/x-json')])
-        data = [];
-        items = self.debug_infos.values()
-        items.sort(lambda a, b: cmp(a.created, b.created))
-        data = [item.json() for item in items]
-        return [repr(data)]
-    summary.exposed = True
-
-    def view(self, environ, start_response):
-        """
-        View old exception reports
-        """
-        id = int(request.path_info_pop(environ))
-        if id not in self.debug_infos:
-            start_response(
-                '500 Server Error',
-                [('Content-type', 'text/html')])
-            return [
-                "Traceback by id %s does not exist (maybe "
-                "the server has been restarted?)"
-                % id]
-        debug_info = self.debug_infos[id]
-        return debug_info.wsgi_application(environ, start_response)
-    view.exposed = True
-
-    def make_view_url(self, environ, base_path, count):
-        return base_path + '/_debug/view/%s' % count
-
-    #@wsgiapp()
-    #@get_debug_info
-    def show_frame(self, tbid, debug_info, **kw):
-        frame = debug_info.frame(int(tbid))
-        vars = frame.tb_frame.f_locals
-        if vars:
-            registry.restorer.restoration_begin(debug_info.counter)
-            local_vars = make_table(vars)
-            registry.restorer.restoration_end()
-        else:
-            local_vars = 'No local vars'
-        return input_form(tbid, debug_info) + local_vars
-
-    show_frame = wsgiapp()(get_debug_info(show_frame))
-
-    #@wsgiapp()
-    #@get_debug_info
-    def exec_input(self, tbid, debug_info, input, **kw):
-        if not input.strip():
-            return ''
-        input = input.rstrip() + '\n'
-        frame = debug_info.frame(int(tbid))
-        vars = frame.tb_frame.f_locals
-        glob_vars = frame.tb_frame.f_globals
-        context = evalcontext.EvalContext(vars, glob_vars)
-        registry.restorer.restoration_begin(debug_info.counter)
-        output = context.exec_expr(input)
-        registry.restorer.restoration_end()
-        input_html = formatter.str2html(input)
-        return ('<code style="color: #060">&gt;&gt;&gt;</code> '
-                '<code>%s</code><br>\n%s'
-                % (preserve_whitespace(input_html, quote=False),
-                   preserve_whitespace(output)))
-
-    exec_input = wsgiapp()(get_debug_info(exec_input))
-
-    def respond(self, environ, start_response):
-        if environ.get('paste.throw_errors'):
-            return self.application(environ, start_response)
-        base_path = request.construct_url(environ, with_path_info=False,
-                                          with_query_string=False)
-        environ['paste.throw_errors'] = True
-        started = []
-        def detect_start_response(status, headers, exc_info=None):
-            try:
-                return start_response(status, headers, exc_info)
-            except:
-                raise
-            else:
-                started.append(True)
-        try:
-            __traceback_supplement__ = errormiddleware.Supplement, self, environ
-            app_iter = self.application(environ, detect_start_response)
-            try:
-                return_iter = list(app_iter)
-                return return_iter
-            finally:
-                if hasattr(app_iter, 'close'):
-                    app_iter.close()
-        except:
-            exc_info = sys.exc_info()
-            for expected in environ.get('paste.expected_exceptions', []):
-                if isinstance(exc_info[1], expected):
-                    raise
-
-            # Tell the Registry to save its StackedObjectProxies current state
-            # for later restoration
-            registry.restorer.save_registry_state(environ)
-
-            count = get_debug_count(environ)
-            view_uri = self.make_view_url(environ, base_path, count)
-            if not started:
-                headers = [('content-type', 'text/html')]
-                headers.append(('X-Debug-URL', view_uri))
-                start_response('500 Internal Server Error',
-                               headers,
-                               exc_info)
-            environ['wsgi.errors'].write('Debug at: %s\n' % view_uri)
-
-            exc_data = collector.collect_exception(*exc_info)
-            debug_info = DebugInfo(count, exc_info, exc_data, base_path,
-                                   environ, view_uri)
-            assert count not in self.debug_infos
-            self.debug_infos[count] = debug_info
-
-            if self.xmlhttp_key:
-                get_vars = wsgilib.parse_querystring(environ)
-                if dict(get_vars).get(self.xmlhttp_key):
-                    exc_data = collector.collect_exception(*exc_info)
-                    html = formatter.format_html(
-                        exc_data, include_hidden_frames=False,
-                        include_reusable=False, show_extra_data=False)
-                    return [html]
-
-            # @@: it would be nice to deal with bad content types here
-            return debug_info.content()
-
-    def exception_handler(self, exc_info, environ):
-        simple_html_error = False
-        if self.xmlhttp_key:
-            get_vars = wsgilib.parse_querystring(environ)
-            if dict(get_vars).get(self.xmlhttp_key):
-                simple_html_error = True
-        return errormiddleware.handle_exception(
-            exc_info, environ['wsgi.errors'],
-            html=True,
-            debug_mode=True,
-            simple_html_error=simple_html_error)
-
-class DebugInfo(object):
-
-    def __init__(self, counter, exc_info, exc_data, base_path,
-                 environ, view_uri):
-        self.counter = counter
-        self.exc_data = exc_data
-        self.base_path = base_path
-        self.environ = environ
-        self.view_uri = view_uri
-        self.created = time.time()
-        self.exc_type, self.exc_value, self.tb = exc_info
-        __exception_formatter__ = 1
-        self.frames = []
-        n = 0
-        tb = self.tb
-        while tb is not None and (limit is None or n < limit):
-            if tb.tb_frame.f_locals.get('__exception_formatter__'):
-                # Stop recursion. @@: should make a fake ExceptionFrame
-                break
-            self.frames.append(tb)
-            tb = tb.tb_next
-            n += 1
-
-    def json(self):
-        """Return the JSON-able representation of this object"""
-        return {
-            'uri': self.view_uri,
-            'created': time.strftime('%c', time.gmtime(self.created)),
-            'created_timestamp': self.created,
-            'exception_type': str(self.exc_type),
-            'exception': str(self.exc_value),
-            }
-
-    def frame(self, tbid):
-        for frame in self.frames:
-            if id(frame) == tbid:
-                return frame
-        else:
-            raise ValueError, (
-                "No frame by id %s found from %r" % (tbid, self.frames))
-
-    def wsgi_application(self, environ, start_response):
-        start_response('200 OK', [('content-type', 'text/html')])
-        return self.content()
-
-    def content(self):
-        html = format_eval_html(self.exc_data, self.base_path, self.counter)
-        head_html = (formatter.error_css + formatter.hide_display_js)
-        head_html += self.eval_javascript()
-        repost_button = make_repost_button(self.environ)
-        page = error_template % {
-            'repost_button': repost_button or '',
-            'head_html': head_html,
-            'body': html}
-        return [page]
-
-    def eval_javascript(self):
-        base_path = self.base_path + '/_debug'
-        return (
-            '<script type="text/javascript" src="%s/mochikit/MochiKit.js">'
-            '</script>\n'
-            '<script type="text/javascript" src="%s/media/debug.js">'
-            '</script>\n'
-            '<script type="text/javascript">\n'
-            'debug_base = %r;\n'
-            'debug_count = %r;\n'
-            '</script>\n'
-            % (base_path, base_path, base_path, self.counter))
-
-class EvalHTMLFormatter(formatter.HTMLFormatter):
-
-    def __init__(self, base_path, counter, **kw):
-        super(EvalHTMLFormatter, self).__init__(**kw)
-        self.base_path = base_path
-        self.counter = counter
-    
-    def format_source_line(self, filename, frame):
-        line = formatter.HTMLFormatter.format_source_line(
-            self, filename, frame)
-        return (line +
-                '  <a href="#" class="switch_source" '
-                'tbid="%s" onClick="return showFrame(this)">&nbsp; &nbsp; '
-                '<img src="%s/_debug/media/plus.jpg" border=0 width=9 '
-                'height=9> &nbsp; &nbsp;</a>'
-                % (frame.tbid, self.base_path))
-
-def make_table(items):
-    if isinstance(items, dict):
-        items = items.items()
-        items.sort()
-    rows = []
-    i = 0
-    for name, value in items:
-        i += 1
-        out = StringIO()
-        try:
-            pprint.pprint(value, out)
-        except Exception, e:
-            print >> out, 'Error: %s' % e
-        value = html_quote(out.getvalue())
-        if len(value) > 100:
-            # @@: This can actually break the HTML :(
-            # should I truncate before quoting?
-            orig_value = value
-            value = value[:100]
-            value += '<a class="switch_source" style="background-color: #999" href="#" onclick="return expandLong(this)">...</a>'
-            value += '<span style="display: none">%s</span>' % orig_value[100:]
-        value = formatter.make_wrappable(value)
-        if i % 2:
-            attr = ' class="even"'
-        else:
-            attr = ' class="odd"'
-        rows.append('<tr%s style="vertical-align: top;"><td>'
-                    '<b>%s</b></td><td style="overflow: auto">%s<td></tr>'
-                    % (attr, html_quote(name),
-                       preserve_whitespace(value, quote=False)))
-    return '<table>%s</table>' % (
-        '\n'.join(rows))
-
-def format_eval_html(exc_data, base_path, counter):
-    short_formatter = EvalHTMLFormatter(
-        base_path=base_path,
-        counter=counter,
-        include_reusable=False)
-    short_er = short_formatter.format_collected_data(exc_data)
-    long_formatter = EvalHTMLFormatter(
-        base_path=base_path,
-        counter=counter,
-        show_hidden_frames=True,
-        show_extra_data=False,
-        include_reusable=False)
-    long_er = long_formatter.format_collected_data(exc_data)
-    text_er = formatter.format_text(exc_data, show_hidden_frames=True)
-    if short_formatter.filter_frames(exc_data.frames) != \
-        long_formatter.filter_frames(exc_data.frames):
-        # Only display the full traceback when it differs from the
-        # short version
-        full_traceback_html = """
-    <br>
-    <script type="text/javascript">
-    show_button('full_traceback', 'full traceback')
-    </script>
-    <div id="full_traceback" class="hidden-data">
-    %s
-    </div>
-        """ % long_er
-    else:
-        full_traceback_html = ''
-    
-    return """
-    %s
-    %s
-    <br>
-    <script type="text/javascript">
-    show_button('text_version', 'text version')
-    </script>
-    <div id="text_version" class="hidden-data">
-    <textarea style="width: 100%%" rows=10 cols=60>%s</textarea>
-    </div>
-    """ % (short_er, full_traceback_html, cgi.escape(text_er))
-
-def make_repost_button(environ):
-    url = request.construct_url(environ)
-    if environ['REQUEST_METHOD'] == 'GET':
-        return ('<button onclick="window.location.href=%r">'
-                'Re-GET Page</button><br>' % url)
-    else:
-        # @@: I'd like to reconstruct this, but I can't because
-        # the POST body is probably lost at this point, and
-        # I can't get it back :(
-        return None
-    # @@: Use or lose the following code block
-    """
-    fields = []
-    for name, value in wsgilib.parse_formvars(
-        environ, include_get_vars=False).items():
-        if hasattr(value, 'filename'):
-            # @@: Arg, we'll just submit the body, and leave out
-            # the filename :(
-            value = value.value
-        fields.append(
-            '<input type="hidden" name="%s" value="%s">'
-            % (html_quote(name), html_quote(value)))
-    return '''
-<form action="%s" method="POST">
-%s
-<input type="submit" value="Re-POST Page">
-</form>''' % (url, '\n'.join(fields))
-"""
-    
-
-def input_form(tbid, debug_info):
-    return '''
-<form action="#" method="POST"
- onsubmit="return submitInput($(\'submit_%(tbid)s\'), %(tbid)s)">
-<div id="exec-output-%(tbid)s" style="width: 95%%;
- padding: 5px; margin: 5px; border: 2px solid #000;
- display: none"></div>
-<input type="text" name="input" id="debug_input_%(tbid)s"
- style="width: 100%%"
- autocomplete="off" onkeypress="upArrow(this, event)"><br>
-<input type="submit" value="Execute" name="submitbutton"
- onclick="return submitInput(this, %(tbid)s)"
- id="submit_%(tbid)s"
- input-from="debug_input_%(tbid)s"
- output-to="exec-output-%(tbid)s">
-<input type="submit" value="Expand"
- onclick="return expandInput(this)">
-</form>
- ''' % {'tbid': tbid}
-
-error_template = '''
-<html>
-<head>
- <title>Server Error</title>
- %(head_html)s
-</head>
-<body>
-
-<div id="error-area" style="display: none; background-color: #600; color: #fff; border: 2px solid black">
-<div id="error-container"></div>
-<button onclick="return clearError()">clear this</button>
-</div>
-
-%(repost_button)s
-
-%(body)s
-
-</body>
-</html>
-'''
-
-def make_eval_exception(app, global_conf, xmlhttp_key=None):
-    """
-    Wraps the application in an interactive debugger.
-
-    This debugger is a major security hole, and should only be
-    used during development.
-
-    xmlhttp_key is a string that, if present in QUERY_STRING,
-    indicates that the request is an XMLHttp request, and the
-    Javascript/interactive debugger should not be returned.  (If you
-    try to put the debugger somewhere with innerHTML, you will often
-    crash the browser)
-    """
-    if xmlhttp_key is None:
-        xmlhttp_key = global_conf.get('xmlhttp_key', '_')
-    return EvalException(app, xmlhttp_key=xmlhttp_key)
-
diff --git a/lib/paste/evalexception/mochikit/MochiKit.js b/lib/paste/evalexception/mochikit/MochiKit.js
@@ -1,4802 +0,0 @@
-/***
-
-    MochiKit.MochiKit 1.3.1 : PACKED VERSION
-
-    THIS FILE IS AUTOMATICALLY GENERATED.  If creating patches, please
-    diff against the source tree, not this file.
-
-    See <http://mochikit.com/> for documentation, downloads, license, etc.
-
-    (c) 2005 Bob Ippolito.  All rights Reserved.
-
-***/
-
-if(typeof (dojo)!="undefined"){
-dojo.provide("MochiKit.Base");
-}
-if(typeof (MochiKit)=="undefined"){
-MochiKit={};
-}
-if(typeof (MochiKit.Base)=="undefined"){
-MochiKit.Base={};
-}
-MochiKit.Base.VERSION="1.3.1";
-MochiKit.Base.NAME="MochiKit.Base";
-MochiKit.Base.update=function(_1,_2){
-if(_1===null){
-_1={};
-}
-for(var i=1;i<arguments.length;i++){
-var o=arguments[i];
-if(typeof (o)!="undefined"&&o!==null){
-for(var k in o){
-_1[k]=o[k];
-}
-}
-}
-return _1;
-};
-MochiKit.Base.update(MochiKit.Base,{__repr__:function(){
-return "["+this.NAME+" "+this.VERSION+"]";
-},toString:function(){
-return this.__repr__();
-},counter:function(n){
-if(arguments.length===0){
-n=1;
-}
-return function(){
-return n++;
-};
-},clone:function(_7){
-var me=arguments.callee;
-if(arguments.length==1){
-me.prototype=_7;
-return new me();
-}
-},flattenArguments:function(_9){
-var res=[];
-var m=MochiKit.Base;
-var _12=m.extend(null,arguments);
-while(_12.length){
-var o=_12.shift();
-if(o&&typeof (o)=="object"&&typeof (o.length)=="number"){
-for(var i=o.length-1;i>=0;i--){
-_12.unshift(o[i]);
-}
-}else{
-res.push(o);
-}
-}
-return res;
-},extend:function(_13,obj,_15){
-if(!_15){
-_15=0;
-}
-if(obj){
-var l=obj.length;
-if(typeof (l)!="number"){
-if(typeof (MochiKit.Iter)!="undefined"){
-obj=MochiKit.Iter.list(obj);
-l=obj.length;
-}else{
-throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
-}
-}
-if(!_13){
-_13=[];
-}
-for(var i=_15;i<l;i++){
-_13.push(obj[i]);
-}
-}
-return _13;
-},updatetree:function(_17,obj){
-if(_17===null){
-_17={};
-}
-for(var i=1;i<arguments.length;i++){
-var o=arguments[i];
-if(typeof (o)!="undefined"&&o!==null){
-for(var k in o){
-var v=o[k];
-if(typeof (_17[k])=="object"&&typeof (v)=="object"){
-arguments.callee(_17[k],v);
-}else{
-_17[k]=v;
-}
-}
-}
-}
-return _17;
-},setdefault:function(_19,obj){
-if(_19===null){
-_19={};
-}
-for(var i=1;i<arguments.length;i++){
-var o=arguments[i];
-for(var k in o){
-if(!(k in _19)){
-_19[k]=o[k];
-}
-}
-}
-return _19;
-},keys:function(obj){
-var _20=[];
-for(var _21 in obj){
-_20.push(_21);
-}
-return _20;
-},items:function(obj){
-var _22=[];
-var e;
-for(var _24 in obj){
-var v;
-try{
-v=obj[_24];
-}
-catch(e){
-continue;
-}
-_22.push([_24,v]);
-}
-return _22;
-},_newNamedError:function(_25,_26,_27){
-_27.prototype=new MochiKit.Base.NamedError(_25.NAME+"."+_26);
-_25[_26]=_27;
-},operator:{truth:function(a){
-return !!a;
-},lognot:function(a){
-return !a;
-},identity:function(a){
-return a;
-},not:function(a){
-return ~a;
-},neg:function(a){
-return -a;
-},add:function(a,b){
-return a+b;
-},sub:function(a,b){
-return a-b;
-},div:function(a,b){
-return a/b;
-},mod:function(a,b){
-return a%b;
-},mul:function(a,b){
-return a*b;
-},and:function(a,b){
-return a&b;
-},or:function(a,b){
-return a|b;
-},xor:function(a,b){
-return a^b;
-},lshift:function(a,b){
-return a<<b;
-},rshift:function(a,b){
-return a>>b;
-},zrshift:function(a,b){
-return a>>>b;
-},eq:function(a,b){
-return a==b;
-},ne:function(a,b){
-return a!=b;
-},gt:function(a,b){
-return a>b;
-},ge:function(a,b){
-return a>=b;
-},lt:function(a,b){
-return a<b;
-},le:function(a,b){
-return a<=b;
-},ceq:function(a,b){
-return MochiKit.Base.compare(a,b)===0;
-},cne:function(a,b){
-return MochiKit.Base.compare(a,b)!==0;
-},cgt:function(a,b){
-return MochiKit.Base.compare(a,b)==1;
-},cge:function(a,b){
-return MochiKit.Base.compare(a,b)!=-1;
-},clt:function(a,b){
-return MochiKit.Base.compare(a,b)==-1;
-},cle:function(a,b){
-return MochiKit.Base.compare(a,b)!=1;
-},logand:function(a,b){
-return a&&b;
-},logor:function(a,b){
-return a||b;
-},contains:function(a,b){
-return b in a;
-}},forwardCall:function(_30){
-return function(){
-return this[_30].apply(this,arguments);
-};
-},itemgetter:function(_31){
-return function(arg){
-return arg[_31];
-};
-},typeMatcher:function(){
-var _33={};
-for(var i=0;i<arguments.length;i++){
-var typ=arguments[i];
-_33[typ]=typ;
-}
-return function(){
-for(var i=0;i<arguments.length;i++){
-if(!(typeof (arguments[i]) in _33)){
-return false;
-}
-}
-return true;
-};
-},isNull:function(){
-for(var i=0;i<arguments.length;i++){
-if(arguments[i]!==null){
-return false;
-}
-}
-return true;
-},isUndefinedOrNull:function(){
-for(var i=0;i<arguments.length;i++){
-var o=arguments[i];
-if(!(typeof (o)=="undefined"||o===null)){
-return false;
-}
-}
-return true;
-},isEmpty:function(obj){
-return !MochiKit.Base.isNotEmpty.apply(this,arguments);
-},isNotEmpty:function(obj){
-for(var i=0;i<arguments.length;i++){
-var o=arguments[i];
-if(!(o&&o.length)){
-return false;
-}
-}
-return true;
-},isArrayLike:function(){
-for(var i=0;i<arguments.length;i++){
-var o=arguments[i];
-var typ=typeof (o);
-if((typ!="object"&&!(typ=="function"&&typeof (o.item)=="function"))||o===null||typeof (o.length)!="number"){
-return false;
-}
-}
-return true;
-},isDateLike:function(){
-for(var i=0;i<arguments.length;i++){
-var o=arguments[i];
-if(typeof (o)!="object"||o===null||typeof (o.getTime)!="function"){
-return false;
-}
-}
-return true;
-},xmap:function(fn){
-if(fn===null){
-return MochiKit.Base.extend(null,arguments,1);
-}
-var _36=[];
-for(var i=1;i<arguments.length;i++){
-_36.push(fn(arguments[i]));
-}
-return _36;
-},map:function(fn,lst){
-var m=MochiKit.Base;
-var itr=MochiKit.Iter;
-var _39=m.isArrayLike;
-if(arguments.length<=2){
-if(!_39(lst)){
-if(itr){
-lst=itr.list(lst);
-if(fn===null){
-return lst;
-}
-}else{
-throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
-}
-}
-if(fn===null){
-return m.extend(null,lst);
-}
-var _40=[];
-for(var i=0;i<lst.length;i++){
-_40.push(fn(lst[i]));
-}
-return _40;
-}else{
-if(fn===null){
-fn=Array;
-}
-var _41=null;
-for(i=1;i<arguments.length;i++){
-if(!_39(arguments[i])){
-if(itr){
-return itr.list(itr.imap.apply(null,arguments));
-}else{
-throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
-}
-}
-var l=arguments[i].length;
-if(_41===null||_41>l){
-_41=l;
-}
-}
-_40=[];
-for(i=0;i<_41;i++){
-var _42=[];
-for(var j=1;j<arguments.length;j++){
-_42.push(arguments[j][i]);
-}
-_40.push(fn.apply(this,_42));
-}
-return _40;
-}
-},xfilter:function(fn){
-var _44=[];
-if(fn===null){
-fn=MochiKit.Base.operator.truth;
-}
-for(var i=1;i<arguments.length;i++){
-var o=arguments[i];
-if(fn(o)){
-_44.push(o);
-}
-}
-return _44;
-},filter:function(fn,lst,_45){
-var _46=[];
-var m=MochiKit.Base;
-if(!m.isArrayLike(lst)){
-if(MochiKit.Iter){
-lst=MochiKit.Iter.list(lst);
-}else{
-throw new TypeError("Argument not an array-like and MochiKit.Iter not present");
-}
-}
-if(fn===null){
-fn=m.operator.truth;
-}
-if(typeof (Array.prototype.filter)=="function"){
-return Array.prototype.filter.call(lst,fn,_45);
-}else{
-if(typeof (_45)=="undefined"||_45===null){
-for(var i=0;i<lst.length;i++){
-var o=lst[i];
-if(fn(o)){
-_46.push(o);
-}
-}
-}else{
-for(i=0;i<lst.length;i++){
-o=lst[i];
-if(fn.call(_45,o)){
-_46.push(o);
-}
-}
-}
-}
-return _46;
-},_wrapDumbFunction:function(_47){
-return function(){
-switch(arguments.length){
-case 0:
-return _47();
-case 1:
-return _47(arguments[0]);
-case 2:
-return _47(arguments[0],arguments[1]);
-case 3:
-return _47(arguments[0],arguments[1],arguments[2]);
-}
-var _48=[];
-for(var i=0;i<arguments.length;i++){
-_48.push("arguments["+i+"]");
-}
-return eval("(func("+_48.join(",")+"))");
-};
-},method:function(_49,_50){
-var m=MochiKit.Base;
-return m.bind.apply(this,m.extend([_50,_49],arguments,2));
-},bind:function(_51,_52){
-if(typeof (_51)=="string"){
-_51=_52[_51];
-}
-var _53=_51.im_func;
-var _54=_51.im_preargs;
-var _55=_51.im_self;
-var m=MochiKit.Base;
-if(typeof (_51)=="function"&&typeof (_51.apply)=="undefined"){
-_51=m._wrapDumbFunction(_51);
-}
-if(typeof (_53)!="function"){
-_53=_51;
-}
-if(typeof (_52)!="undefined"){
-_55=_52;
-}
-if(typeof (_54)=="undefined"){
-_54=[];
-}else{
-_54=_54.slice();
-}
-m.extend(_54,arguments,2);
-var _56=function(){
-var _57=arguments;
-var me=arguments.callee;
-if(me.im_preargs.length>0){
-_57=m.concat(me.im_preargs,_57);
-}
-var _52=me.im_self;
-if(!_52){
-_52=this;
-}
-return me.im_func.apply(_52,_57);
-};
-_56.im_self=_55;
-_56.im_func=_53;
-_56.im_preargs=_54;
-return _56;
-},bindMethods:function(_58){
-var _59=MochiKit.Base.bind;
-for(var k in _58){
-var _60=_58[k];
-if(typeof (_60)=="function"){
-_58[k]=_59(_60,_58);
-}
-}
-},registerComparator:function(_61,_62,_63,_64){
-MochiKit.Base.comparatorRegistry.register(_61,_62,_63,_64);
-},_primitives:{"boolean":true,"string":true,"number":true},compare:function(a,b){
-if(a==b){
-return 0;
-}
-var _65=(typeof (a)=="undefined"||a===null);
-var _66=(typeof (b)=="undefined"||b===null);
-if(_65&&_66){
-return 0;
-}else{
-if(_65){
-return -1;
-}else{
-if(_66){
-return 1;
-}
-}
-}
-var m=MochiKit.Base;
-var _67=m._primitives;
-if(!(typeof (a) in _67&&typeof (b) in _67)){
-try{
-return m.comparatorRegistry.match(a,b);
-}
-catch(e){
-if(e!=m.NotFound){
-throw e;
-}
-}
-}
-if(a<b){
-return -1;
-}else{
-if(a>b){
-return 1;
-}
-}
-var _68=m.repr;
-throw new TypeError(_68(a)+" and "+_68(b)+" can not be compared");
-},compareDateLike:function(a,b){
-return MochiKit.Base.compare(a.getTime(),b.getTime());
-},compareArrayLike:function(a,b){
-var _69=MochiKit.Base.compare;
-var _70=a.length;
-var _71=0;
-if(_70>b.length){
-_71=1;
-_70=b.length;
-}else{
-if(_70<b.length){
-_71=-1;
-}
-}
-for(var i=0;i<_70;i++){
-var cmp=_69(a[i],b[i]);
-if(cmp){
-return cmp;
-}
-}
-return _71;
-},registerRepr:function(_73,_74,_75,_76){
-MochiKit.Base.reprRegistry.register(_73,_74,_75,_76);
-},repr:function(o){
-if(typeof (o)=="undefined"){
-return "undefined";
-}else{
-if(o===null){
-return "null";
-}
-}
-try{
-if(typeof (o.__repr__)=="function"){
-return o.__repr__();
-}else{
-if(typeof (o.repr)=="function"&&o.repr!=arguments.callee){
-return o.repr();
-}
-}
-return MochiKit.Base.reprRegistry.match(o);
-}
-catch(e){
-if(typeof (o.NAME)=="string"&&(o.toString==Function.prototype.toString||o.toString==Object.prototype.toString)){
-return o.NAME;
-}
-}
-try{
-var _77=(o+"");
-}
-catch(e){
-return "["+typeof (o)+"]";
-}
-if(typeof (o)=="function"){
-o=_77.replace(/^\s+/,"");
-var idx=o.indexOf("{");
-if(idx!=-1){
-o=o.substr(0,idx)+"{...}";
-}
-}
-return _77;
-},reprArrayLike:function(o){
-var m=MochiKit.Base;
-return "["+m.map(m.repr,o).join(", ")+"]";
-},reprString:function(o){
-return ("\""+o.replace(/(["\\])/g,"\\$1")+"\"").replace(/[\f]/g,"\\f").replace(/[\b]/g,"\\b").replace(/[\n]/g,"\\n").replace(/[\t]/g,"\\t").replace(/[\r]/g,"\\r");
-},reprNumber:function(o){
-return o+"";
-},registerJSON:function(_79,_80,_81,_82){
-MochiKit.Base.jsonRegistry.register(_79,_80,_81,_82);
-},evalJSON:function(){
-return eval("("+arguments[0]+")");
-},serializeJSON:function(o){
-var _83=typeof (o);
-if(_83=="undefined"){
-return "undefined";
-}else{
-if(_83=="number"||_83=="boolean"){
-return o+"";
-}else{
-if(o===null){
-return "null";
-}
-}
-}
-var m=MochiKit.Base;
-var _84=m.reprString;
-if(_83=="string"){
-return _84(o);
-}
-var me=arguments.callee;
-var _85;
-if(typeof (o.__json__)=="function"){
-_85=o.__json__();
-if(o!==_85){
-return me(_85);
-}
-}
-if(typeof (o.json)=="function"){
-_85=o.json();
-if(o!==_85){
-return me(_85);
-}
-}
-if(_83!="function"&&typeof (o.length)=="number"){
-var res=[];
-for(var i=0;i<o.length;i++){
-var val=me(o[i]);
-if(typeof (val)!="string"){
-val="undefined";
-}
-res.push(val);
-}
-return "["+res.join(", ")+"]";
-}
-try{
-_85=m.jsonRegistry.match(o);
-return me(_85);
-}
-catch(e){
-if(e!=m.NotFound){
-throw e;
-}
-}
-if(_83=="function"){
-return null;
-}
-res=[];
-for(var k in o){
-var _87;
-if(typeof (k)=="number"){
-_87="\""+k+"\"";
-}else{
-if(typeof (k)=="string"){
-_87=_84(k);
-}else{
-continue;
-}
-}
-val=me(o[k]);
-if(typeof (val)!="string"){
-continue;
-}
-res.push(_87+":"+val);
-}
-return "{"+res.join(", ")+"}";
-},objEqual:function(a,b){
-return (MochiKit.Base.compare(a,b)===0);
-},arrayEqual:function(_88,arr){
-if(_88.length!=arr.length){
-return false;
-}
-return (MochiKit.Base.compare(_88,arr)===0);
-},concat:function(){
-var _90=[];
-var _91=MochiKit.Base.extend;
-for(var i=0;i<arguments.length;i++){
-_91(_90,arguments[i]);
-}
-return _90;
-},keyComparator:function(key){
-var m=MochiKit.Base;
-var _93=m.compare;
-if(arguments.length==1){
-return function(a,b){
-return _93(a[key],b[key]);
-};
-}
-var _94=m.extend(null,arguments);
-return function(a,b){
-var _95=0;
-for(var i=0;(_95===0)&&(i<_94.length);i++){
-var key=_94[i];
-_95=_93(a[key],b[key]);
-}
-return _95;
-};
-},reverseKeyComparator:function(key){
-var _96=MochiKit.Base.keyComparator.apply(this,arguments);
-return function(a,b){
-return _96(b,a);
-};
-},partial:function(_97){
-var m=MochiKit.Base;
-return m.bind.apply(this,m.extend([_97,undefined],arguments,1));
-},listMinMax:function(_98,lst){
-if(lst.length===0){
-return null;
-}
-var cur=lst[0];
-var _100=MochiKit.Base.compare;
-for(var i=1;i<lst.length;i++){
-var o=lst[i];
-if(_100(o,cur)==_98){
-cur=o;
-}
-}
-return cur;
-},objMax:function(){
-return MochiKit.Base.listMinMax(1,arguments);
-},objMin:function(){
-return MochiKit.Base.listMinMax(-1,arguments);
-},findIdentical:function(lst,_101,_102,end){
-if(typeof (end)=="undefined"||end===null){
-end=lst.length;
-}
-for(var i=(_102||0);i<end;i++){
-if(lst[i]===_101){
-return i;
-}
-}
-return -1;
-},findValue:function(lst,_104,_105,end){
-if(typeof (end)=="undefined"||end===null){
-end=lst.length;
-}
-var cmp=MochiKit.Base.compare;
-for(var i=(_105||0);i<end;i++){
-if(cmp(lst[i],_104)===0){
-return i;
-}
-}
-return -1;
-},nodeWalk:function(node,_107){
-var _108=[node];
-var _109=MochiKit.Base.extend;
-while(_108.length){
-var res=_107(_108.shift());
-if(res){
-_109(_108,res);
-}
-}
-},nameFunctions:function(_110){
-var base=_110.NAME;
-if(typeof (base)=="undefined"){
-base="";
-}else{
-base=base+".";
-}
-for(var name in _110){
-var o=_110[name];
-if(typeof (o)=="function"&&typeof (o.NAME)=="undefined"){
-try{
-o.NAME=base+name;
-}
-catch(e){
-}
-}
-}
-},queryString:function(_113,_114){
-if(typeof (MochiKit.DOM)!="undefined"&&arguments.length==1&&(typeof (_113)=="string"||(typeof (_113.nodeType)!="undefined"&&_113.nodeType>0))){
-var kv=MochiKit.DOM.formContents(_113);
-_113=kv[0];
-_114=kv[1];
-}else{
-if(arguments.length==1){
-var o=_113;
-_113=[];
-_114=[];
-for(var k in o){
-var v=o[k];
-if(typeof (v)!="function"){
-_113.push(k);
-_114.push(v);
-}
-}
-}
-}
-var rval=[];
-var len=Math.min(_113.length,_114.length);
-var _118=MochiKit.Base.urlEncode;
-for(var i=0;i<len;i++){
-v=_114[i];
-if(typeof (v)!="undefined"&&v!==null){
-rval.push(_118(_113[i])+"="+_118(v));
-}
-}
-return rval.join("&");
-},parseQueryString:function(_119,_120){
-var _121=_119.replace(/\+/g,"%20").split("&");
-var o={};
-var _122;
-if(typeof (decodeURIComponent)!="undefined"){
-_122=decodeURIComponent;
-}else{
-_122=unescape;
-}
-if(_120){
-for(var i=0;i<_121.length;i++){
-var pair=_121[i].split("=");
-var name=_122(pair[0]);
-var arr=o[name];
-if(!(arr instanceof Array)){
-arr=[];
-o[name]=arr;
-}
-arr.push(_122(pair[1]));
-}
-}else{
-for(i=0;i<_121.length;i++){
-pair=_121[i].split("=");
-o[_122(pair[0])]=_122(pair[1]);
-}
-}
-return o;
-}});
-MochiKit.Base.AdapterRegistry=function(){
-this.pairs=[];
-};
-MochiKit.Base.AdapterRegistry.prototype={register:function(name,_124,wrap,_126){
-if(_126){
-this.pairs.unshift([name,_124,wrap]);
-}else{
-this.pairs.push([name,_124,wrap]);
-}
-},match:function(){
-for(var i=0;i<this.pairs.length;i++){
-var pair=this.pairs[i];
-if(pair[1].apply(this,arguments)){
-return pair[2].apply(this,arguments);
-}
-}
-throw MochiKit.Base.NotFound;
-},unregister:function(name){
-for(var i=0;i<this.pairs.length;i++){
-var pair=this.pairs[i];
-if(pair[0]==name){
-this.pairs.splice(i,1);
-return true;
-}
-}
-return false;
-}};
-MochiKit.Base.EXPORT=["counter","clone","extend","update","updatetree","setdefault","keys","items","NamedError","operator","forwardCall","itemgetter","typeMatcher","isCallable","isUndefined","isUndefinedOrNull","isNull","isEmpty","isNotEmpty","isArrayLike","isDateLike","xmap","map","xfilter","filter","bind","bindMethods","NotFound","AdapterRegistry","registerComparator","compare","registerRepr","repr","objEqual","arrayEqual","concat","keyComparator","reverseKeyComparator","partial","merge","listMinMax","listMax","listMin","objMax","objMin","nodeWalk","zip","urlEncode","queryString","serializeJSON","registerJSON","evalJSON","parseQueryString","findValue","findIdentical","flattenArguments","method"];
-MochiKit.Base.EXPORT_OK=["nameFunctions","comparatorRegistry","reprRegistry","jsonRegistry","compareDateLike","compareArrayLike","reprArrayLike","reprString","reprNumber"];
-MochiKit.Base._exportSymbols=function(_127,_128){
-if(typeof (MochiKit.__export__)=="undefined"){
-MochiKit.__export__=(MochiKit.__compat__||(typeof (JSAN)=="undefined"&&typeof (dojo)=="undefined"));
-}
-if(!MochiKit.__export__){
-return;
-}
-var all=_128.EXPORT_TAGS[":all"];
-for(var i=0;i<all.length;i++){
-_127[all[i]]=_128[all[i]];
-}
-};
-MochiKit.Base.__new__=function(){
-var m=this;
-m.forward=m.forwardCall;
-m.find=m.findValue;
-if(typeof (encodeURIComponent)!="undefined"){
-m.urlEncode=function(_130){
-return encodeURIComponent(_130).replace(/\'/g,"%27");
-};
-}else{
-m.urlEncode=function(_131){
-return escape(_131).replace(/\+/g,"%2B").replace(/\"/g,"%22").rval.replace(/\'/g,"%27");
-};
-}
-m.NamedError=function(name){
-this.message=name;
-this.name=name;
-};
-m.NamedError.prototype=new Error();
-m.update(m.NamedError.prototype,{repr:function(){
-if(this.message&&this.message!=this.name){
-return this.name+"("+m.repr(this.message)+")";
-}else{
-return this.name+"()";
-}
-},toString:m.forwardCall("repr")});
-m.NotFound=new m.NamedError("MochiKit.Base.NotFound");
-m.listMax=m.partial(m.listMinMax,1);
-m.listMin=m.partial(m.listMinMax,-1);
-m.isCallable=m.typeMatcher("function");
-m.isUndefined=m.typeMatcher("undefined");
-m.merge=m.partial(m.update,null);
-m.zip=m.partial(m.map,null);
-m.comparatorRegistry=new m.AdapterRegistry();
-m.registerComparator("dateLike",m.isDateLike,m.compareDateLike);
-m.registerComparator("arrayLike",m.isArrayLike,m.compareArrayLike);
-m.reprRegistry=new m.AdapterRegistry();
-m.registerRepr("arrayLike",m.isArrayLike,m.reprArrayLike);
-m.registerRepr("string",m.typeMatcher("string"),m.reprString);
-m.registerRepr("numbers",m.typeMatcher("number","boolean"),m.reprNumber);
-m.jsonRegistry=new m.AdapterRegistry();
-var all=m.concat(m.EXPORT,m.EXPORT_OK);
-m.EXPORT_TAGS={":common":m.concat(m.EXPORT_OK),":all":all};
-m.nameFunctions(this);
-};
-MochiKit.Base.__new__();
-if(!MochiKit.__compat__){
-compare=MochiKit.Base.compare;
-}
-MochiKit.Base._exportSymbols(this,MochiKit.Base);
-if(typeof (dojo)!="undefined"){
-dojo.provide("MochiKit.Iter");
-dojo.require("MochiKit.Base");
-}
-if(typeof (JSAN)!="undefined"){
-JSAN.use("MochiKit.Base",[]);
-}
-try{
-if(typeof (MochiKit.Base)=="undefined"){
-throw "";
-}
-}
-catch(e){
-throw "MochiKit.Iter depends on MochiKit.Base!";
-}
-if(typeof (MochiKit.Iter)=="undefined"){
-MochiKit.Iter={};
-}
-MochiKit.Iter.NAME="MochiKit.Iter";
-MochiKit.Iter.VERSION="1.3.1";
-MochiKit.Base.update(MochiKit.Iter,{__repr__:function(){
-return "["+this.NAME+" "+this.VERSION+"]";
-},toString:function(){
-return this.__repr__();
-},registerIteratorFactory:function(name,_132,_133,_134){
-MochiKit.Iter.iteratorRegistry.register(name,_132,_133,_134);
-},iter:function(_135,_136){
-var self=MochiKit.Iter;
-if(arguments.length==2){
-return self.takewhile(function(a){
-return a!=_136;
-},_135);
-}
-if(typeof (_135.next)=="function"){
-return _135;
-}else{
-if(typeof (_135.iter)=="function"){
-return _135.iter();
-}
-}
-try{
-return self.iteratorRegistry.match(_135);
-}
-catch(e){
-var m=MochiKit.Base;
-if(e==m.NotFound){
-e=new TypeError(typeof (_135)+": "+m.repr(_135)+" is not iterable");
-}
-throw e;
-}
-},count:function(n){
-if(!n){
-n=0;
-}
-var m=MochiKit.Base;
-return {repr:function(){
-return "count("+n+")";
-},toString:m.forwardCall("repr"),next:m.counter(n)};
-},cycle:function(p){
-var self=MochiKit.Iter;
-var m=MochiKit.Base;
-var lst=[];
-var _139=self.iter(p);
-return {repr:function(){
-return "cycle(...)";
-},toString:m.forwardCall("repr"),next:function(){
-try{
-var rval=_139.next();
-lst.push(rval);
-return rval;
-}
-catch(e){
-if(e!=self.StopIteration){
-throw e;
-}
-if(lst.length===0){
-this.next=function(){
-throw self.StopIteration;
-};
-}else{
-var i=-1;
-this.next=function(){
-i=(i+1)%lst.length;
-return lst[i];
-};
-}
-return this.next();
-}
-}};
-},repeat:function(elem,n){
-var m=MochiKit.Base;
-if(typeof (n)=="undefined"){
-return {repr:function(){
-return "repeat("+m.repr(elem)+")";
-},toString:m.forwardCall("repr"),next:function(){
-return elem;
-}};
-}
-return {repr:function(){
-return "repeat("+m.repr(elem)+", "+n+")";
-},toString:m.forwardCall("repr"),next:function(){
-if(n<=0){
-throw MochiKit.Iter.StopIteration;
-}
-n-=1;
-return elem;
-}};
-},next:function(_141){
-return _141.next();
-},izip:function(p,q){
-var m=MochiKit.Base;
-var next=MochiKit.Iter.next;
-var _144=m.map(iter,arguments);
-return {repr:function(){
-return "izip(...)";
-},toString:m.forwardCall("repr"),next:function(){
-return m.map(next,_144);
-}};
-},ifilter:function(pred,seq){
-var m=MochiKit.Base;
-seq=MochiKit.Iter.iter(seq);
-if(pred===null){
-pred=m.operator.truth;
-}
-return {repr:function(){
-return "ifilter(...)";
-},toString:m.forwardCall("repr"),next:function(){
-while(true){
-var rval=seq.next();
-if(pred(rval)){
-return rval;
-}
-}
-return undefined;
-}};
-},ifilterfalse:function(pred,seq){
-var m=MochiKit.Base;
-seq=MochiKit.Iter.iter(seq);
-if(pred===null){
-pred=m.operator.truth;
-}
-return {repr:function(){
-return "ifilterfalse(...)";
-},toString:m.forwardCall("repr"),next:function(){
-while(true){
-var rval=seq.next();
-if(!pred(rval)){
-return rval;
-}
-}
-return undefined;
-}};
-},islice:function(seq){
-var self=MochiKit.Iter;
-var m=MochiKit.Base;
-seq=self.iter(seq);
-var _147=0;
-var stop=0;
-var step=1;
-var i=-1;
-if(arguments.length==2){
-stop=arguments[1];
-}else{
-if(arguments.length==3){
-_147=arguments[1];
-stop=arguments[2];
-}else{
-_147=arguments[1];
-stop=arguments[2];
-step=arguments[3];
-}
-}
-return {repr:function(){
-return "islice("+["...",_147,stop,step].join(", ")+")";
-},toString:m.forwardCall("repr"),next:function(){
-var rval;
-while(i<_147){
-rval=seq.next();
-i++;
-}
-if(_147>=stop){
-throw self.StopIteration;
-}
-_147+=step;
-return rval;
-}};
-},imap:function(fun,p,q){
-var m=MochiKit.Base;
-var self=MochiKit.Iter;
-var _151=m.map(self.iter,m.extend(null,arguments,1));
-var map=m.map;
-var next=self.next;
-return {repr:function(){
-return "imap(...)";
-},toString:m.forwardCall("repr"),next:function(){
-return fun.apply(this,map(next,_151));
-}};
-},applymap:function(fun,seq,self){
-seq=MochiKit.Iter.iter(seq);
-var m=MochiKit.Base;
-return {repr:function(){
-return "applymap(...)";
-},toString:m.forwardCall("repr"),next:function(){
-return fun.apply(self,seq.next());
-}};
-},chain:function(p,q){
-var self=MochiKit.Iter;
-var m=MochiKit.Base;
-if(arguments.length==1){
-return self.iter(arguments[0]);
-}
-var _153=m.map(self.iter,arguments);
-return {repr:function(){
-return "chain(...)";
-},toString:m.forwardCall("repr"),next:function(){
-while(_153.length>1){
-try{
-return _153[0].next();
-}
-catch(e){
-if(e!=self.StopIteration){
-throw e;
-}
-_153.shift();
-}
-}
-if(_153.length==1){
-var arg=_153.shift();
-this.next=m.bind("next",arg);
-return this.next();
-}
-throw self.StopIteration;
-}};
-},takewhile:function(pred,seq){
-var self=MochiKit.Iter;
-seq=self.iter(seq);
-return {repr:function(){
-return "takewhile(...)";
-},toString:MochiKit.Base.forwardCall("repr"),next:function(){
-var rval=seq.next();
-if(!pred(rval)){
-this.next=function(){
-throw self.StopIteration;
-};
-this.next();
-}
-return rval;
-}};
-},dropwhile:function(pred,seq){
-seq=MochiKit.Iter.iter(seq);
-var m=MochiKit.Base;
-var bind=m.bind;
-return {"repr":function(){
-return "dropwhile(...)";
-},"toString":m.forwardCall("repr"),"next":function(){
-while(true){
-var rval=seq.next();
-if(!pred(rval)){
-break;
-}
-}
-this.next=bind("next",seq);
-return rval;
-}};
-},_tee:function(_155,sync,_157){
-sync.pos[_155]=-1;
-var m=MochiKit.Base;
-var _158=m.listMin;
-return {repr:function(){
-return "tee("+_155+", ...)";
-},toString:m.forwardCall("repr"),next:function(){
-var rval;
-var i=sync.pos[_155];
-if(i==sync.max){
-rval=_157.next();
-sync.deque.push(rval);
-sync.max+=1;
-sync.pos[_155]+=1;
-}else{
-rval=sync.deque[i-sync.min];
-sync.pos[_155]+=1;
-if(i==sync.min&&_158(sync.pos)!=sync.min){
-sync.min+=1;
-sync.deque.shift();
-}
-}
-return rval;
-}};
-},tee:function(_159,n){
-var rval=[];
-var sync={"pos":[],"deque":[],"max":-1,"min":-1};
-if(arguments.length==1){
-n=2;
-}
-var self=MochiKit.Iter;
-_159=self.iter(_159);
-var _tee=self._tee;
-for(var i=0;i<n;i++){
-rval.push(_tee(i,sync,_159));
-}
-return rval;
-},list:function(_161){
-var m=MochiKit.Base;
-if(typeof (_161.slice)=="function"){
-return _161.slice();
-}else{
-if(m.isArrayLike(_161)){
-return m.concat(_161);
-}
-}
-var self=MochiKit.Iter;
-_161=self.iter(_161);
-var rval=[];
-try{
-while(true){
-rval.push(_161.next());
-}
-}
-catch(e){
-if(e!=self.StopIteration){
-throw e;
-}
-return rval;
-}
-return undefined;
-},reduce:function(fn,_162,_163){
-var i=0;
-var x=_163;
-var self=MochiKit.Iter;
-_162=self.iter(_162);
-if(arguments.length<3){
-try{
-x=_162.next();
-}
-catch(e){
-if(e==self.StopIteration){
-e=new TypeError("reduce() of empty sequence with no initial value");
-}
-throw e;
-}
-i++;
-}
-try{
-while(true){
-x=fn(x,_162.next());
-}
-}
-catch(e){
-if(e!=self.StopIteration){
-throw e;
-}
-}
-return x;
-},range:function(){
-var _165=0;
-var stop=0;
-var step=1;
-if(arguments.length==1){
-stop=arguments[0];
-}else{
-if(arguments.length==2){
-_165=arguments[0];
-stop=arguments[1];
-}else{
-if(arguments.length==3){
-_165=arguments[0];
-stop=arguments[1];
-step=arguments[2];
-}else{
-throw new TypeError("range() takes 1, 2, or 3 arguments!");
-}
-}
-}
-if(step===0){
-throw new TypeError("range() step must not be 0");
-}
-return {next:function(){
-if((step>0&&_165>=stop)||(step<0&&_165<=stop)){
-throw MochiKit.Iter.StopIteration;
-}
-var rval=_165;
-_165+=step;
-return rval;
-},repr:function(){
-return "range("+[_165,stop,step].join(", ")+")";
-},toString:MochiKit.Base.forwardCall("repr")};
-},sum:function(_166,_167){
-var x=_167||0;
-var self=MochiKit.Iter;
-_166=self.iter(_166);
-try{
-while(true){
-x+=_166.next();
-}
-}
-catch(e){
-if(e!=self.StopIteration){
-throw e;
-}
-}
-return x;
-},exhaust:function(_168){
-var self=MochiKit.Iter;
-_168=self.iter(_168);
-try{
-while(true){
-_168.next();
-}
-}
-catch(e){
-if(e!=self.StopIteration){
-throw e;
-}
-}
-},forEach:function(_169,func,self){
-var m=MochiKit.Base;
-if(arguments.length>2){
-func=m.bind(func,self);
-}
-if(m.isArrayLike(_169)){
-try{
-for(var i=0;i<_169.length;i++){
-func(_169[i]);
-}
-}
-catch(e){
-if(e!=MochiKit.Iter.StopIteration){
-throw e;
-}
-}
-}else{
-self=MochiKit.Iter;
-self.exhaust(self.imap(func,_169));
-}
-},every:function(_171,func){
-var self=MochiKit.Iter;
-try{
-self.ifilterfalse(func,_171).next();
-return false;
-}
-catch(e){
-if(e!=self.StopIteration){
-throw e;
-}
-return true;
-}
-},sorted:function(_172,cmp){
-var rval=MochiKit.Iter.list(_172);
-if(arguments.length==1){
-cmp=MochiKit.Base.compare;
-}
-rval.sort(cmp);
-return rval;
-},reversed:function(_173){
-var rval=MochiKit.Iter.list(_173);
-rval.reverse();
-return rval;
-},some:function(_174,func){
-var self=MochiKit.Iter;
-try{
-self.ifilter(func,_174).next();
-return true;
-}
-catch(e){
-if(e!=self.StopIteration){
-throw e;
-}
-return false;
-}
-},iextend:function(lst,_175){
-if(MochiKit.Base.isArrayLike(_175)){
-for(var i=0;i<_175.length;i++){
-lst.push(_175[i]);
-}
-}else{
-var self=MochiKit.Iter;
-_175=self.iter(_175);
-try{
-while(true){
-lst.push(_175.next());
-}
-}
-catch(e){
-if(e!=self.StopIteration){
-throw e;
-}
-}
-}
-return lst;
-},groupby:function(_176,_177){
-var m=MochiKit.Base;
-var self=MochiKit.Iter;
-if(arguments.length<2){
-_177=m.operator.identity;
-}
-_176=self.iter(_176);
-var pk=undefined;
-var k=undefined;
-var v;
-function fetch(){
-v=_176.next();
-k=_177(v);
-}
-function eat(){
-var ret=v;
-v=undefined;
-return ret;
-}
-var _180=true;
-return {repr:function(){
-return "groupby(...)";
-},next:function(){
-while(k==pk){
-fetch();
-if(_180){
-_180=false;
-break;
-}
-}
-pk=k;
-return [k,{next:function(){
-if(v==undefined){
-fetch();
-}
-if(k!=pk){
-throw self.StopIteration;
-}
-return eat();
-}}];
-}};
-},groupby_as_array:function(_181,_182){
-var m=MochiKit.Base;
-var self=MochiKit.Iter;
-if(arguments.length<2){
-_182=m.operator.identity;
-}
-_181=self.iter(_181);
-var _183=[];
-var _184=true;
-var _185;
-while(true){
-try{
-var _186=_181.next();
-var key=_182(_186);
-}
-catch(e){
-if(e==self.StopIteration){
-break;
-}
-throw e;
-}
-if(_184||key!=_185){
-var _187=[];
-_183.push([key,_187]);
-}
-_187.push(_186);
-_184=false;
-_185=key;
-}
-return _183;
-},arrayLikeIter:function(_188){
-var i=0;
-return {repr:function(){
-return "arrayLikeIter(...)";
-},toString:MochiKit.Base.forwardCall("repr"),next:function(){
-if(i>=_188.length){
-throw MochiKit.Iter.StopIteration;
-}
-return _188[i++];
-}};
-},hasIterateNext:function(_189){
-return (_189&&typeof (_189.iterateNext)=="function");
-},iterateNextIter:function(_190){
-return {repr:function(){
-return "iterateNextIter(...)";
-},toString:MochiKit.Base.forwardCall("repr"),next:function(){
-var rval=_190.iterateNext();
-if(rval===null||rval===undefined){
-throw MochiKit.Iter.StopIteration;
-}
-return rval;
-}};
-}});
-MochiKit.Iter.EXPORT_OK=["iteratorRegistry","arrayLikeIter","hasIterateNext","iterateNextIter",];
-MochiKit.Iter.EXPORT=["StopIteration","registerIteratorFactory","iter","count","cycle","repeat","next","izip","ifilter","ifilterfalse","islice","imap","applymap","chain","takewhile","dropwhile","tee","list","reduce","range","sum","exhaust","forEach","every","sorted","reversed","some","iextend","groupby","groupby_as_array"];
-MochiKit.Iter.__new__=function(){
-var m=MochiKit.Base;
-this.StopIteration=new m.NamedError("StopIteration");
-this.iteratorRegistry=new m.AdapterRegistry();
-this.registerIteratorFactory("arrayLike",m.isArrayLike,this.arrayLikeIter);
-this.registerIteratorFactory("iterateNext",this.hasIterateNext,this.iterateNextIter);
-this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
-m.nameFunctions(this);
-};
-MochiKit.Iter.__new__();
-if(!MochiKit.__compat__){
-reduce=MochiKit.Iter.reduce;
-}
-MochiKit.Base._exportSymbols(this,MochiKit.Iter);
-if(typeof (dojo)!="undefined"){
-dojo.provide("MochiKit.Logging");
-dojo.require("MochiKit.Base");
-}
-if(typeof (JSAN)!="undefined"){
-JSAN.use("MochiKit.Base",[]);
-}
-try{
-if(typeof (MochiKit.Base)=="undefined"){
-throw "";
-}
-}
-catch(e){
-throw "MochiKit.Logging depends on MochiKit.Base!";
-}
-if(typeof (MochiKit.Logging)=="undefined"){
-MochiKit.Logging={};
-}
-MochiKit.Logging.NAME="MochiKit.Logging";
-MochiKit.Logging.VERSION="1.3.1";
-MochiKit.Logging.__repr__=function(){
-return "["+this.NAME+" "+this.VERSION+"]";
-};
-MochiKit.Logging.toString=function(){
-return this.__repr__();
-};
-MochiKit.Logging.EXPORT=["LogLevel","LogMessage","Logger","alertListener","logger","log","logError","logDebug","logFatal","logWarning"];
-MochiKit.Logging.EXPORT_OK=["logLevelAtLeast","isLogMessage","compareLogMessage"];
-MochiKit.Logging.LogMessage=function(num,_192,info){
-this.num=num;
-this.level=_192;
-this.info=info;
-this.timestamp=new Date();
-};
-MochiKit.Logging.LogMessage.prototype={repr:function(){
-var m=MochiKit.Base;
-return "LogMessage("+m.map(m.repr,[this.num,this.level,this.info]).join(", ")+")";
-},toString:MochiKit.Base.forwardCall("repr")};
-MochiKit.Base.update(MochiKit.Logging,{logLevelAtLeast:function(_194){
-var self=MochiKit.Logging;
-if(typeof (_194)=="string"){
-_194=self.LogLevel[_194];
-}
-return function(msg){
-var _196=msg.level;
-if(typeof (_196)=="string"){
-_196=self.LogLevel[_196];
-}
-return _196>=_194;
-};
-},isLogMessage:function(){
-var _197=MochiKit.Logging.LogMessage;
-for(var i=0;i<arguments.length;i++){
-if(!(arguments[i] instanceof _197)){
-return false;
-}
-}
-return true;
-},compareLogMessage:function(a,b){
-return MochiKit.Base.compare([a.level,a.info],[b.level,b.info]);
-},alertListener:function(msg){
-alert("num: "+msg.num+"\nlevel: "+msg.level+"\ninfo: "+msg.info.join(" "));
-}});
-MochiKit.Logging.Logger=function(_198){
-this.counter=0;
-if(typeof (_198)=="undefined"||_198===null){
-_198=-1;
-}
-this.maxSize=_198;
-this._messages=[];
-this.listeners={};
-this.useNativeConsole=false;
-};
-MochiKit.Logging.Logger.prototype={clear:function(){
-this._messages.splice(0,this._messages.length);
-},logToConsole:function(msg){
-if(typeof (window)!="undefined"&&window.console&&window.console.log){
-window.console.log(msg);
-}else{
-if(typeof (opera)!="undefined"&&opera.postError){
-opera.postError(msg);
-}else{
-if(typeof (printfire)=="function"){
-printfire(msg);
-}
-}
-}
-},dispatchListeners:function(msg){
-for(var k in this.listeners){
-var pair=this.listeners[k];
-if(pair.ident!=k||(pair[0]&&!pair[0](msg))){
-continue;
-}
-pair[1](msg);
-}
-},addListener:function(_199,_200,_201){
-if(typeof (_200)=="string"){
-_200=MochiKit.Logging.logLevelAtLeast(_200);
-}
-var _202=[_200,_201];
-_202.ident=_199;
-this.listeners[_199]=_202;
-},removeListener:function(_203){
-delete this.listeners[_203];
-},baseLog:function(_204,_205){
-var msg=new MochiKit.Logging.LogMessage(this.counter,_204,MochiKit.Base.extend(null,arguments,1));
-this._messages.push(msg);
-this.dispatchListeners(msg);
-if(this.useNativeConsole){
-this.logToConsole(msg.level+": "+msg.info.join(" "));
-}
-this.counter+=1;
-while(this.maxSize>=0&&this._messages.length>this.maxSize){
-this._messages.shift();
-}
-},getMessages:function(_206){
-var _207=0;
-if(!(typeof (_206)=="undefined"||_206===null)){
-_207=Math.max(0,this._messages.length-_206);
-}
-return this._messages.slice(_207);
-},getMessageText:function(_208){
-if(typeof (_208)=="undefined"||_208===null){
-_208=30;
-}
-var _209=this.getMessages(_208);
-if(_209.length){
-var lst=map(function(m){
-return "\n  ["+m.num+"] "+m.level+": "+m.info.join(" ");
-},_209);
-lst.unshift("LAST "+_209.length+" MESSAGES:");
-return lst.join("");
-}
-return "";
-},debuggingBookmarklet:function(_210){
-if(typeof (MochiKit.LoggingPane)=="undefined"){
-alert(this.getMessageText());
-}else{
-MochiKit.LoggingPane.createLoggingPane(_210||false);
-}
-}};
-MochiKit.Logging.__new__=function(){
-this.LogLevel={ERROR:40,FATAL:50,WARNING:30,INFO:20,DEBUG:10};
-var m=MochiKit.Base;
-m.registerComparator("LogMessage",this.isLogMessage,this.compareLogMessage);
-var _211=m.partial;
-var _212=this.Logger;
-var _213=_212.prototype.baseLog;
-m.update(this.Logger.prototype,{debug:_211(_213,"DEBUG"),log:_211(_213,"INFO"),error:_211(_213,"ERROR"),fatal:_211(_213,"FATAL"),warning:_211(_213,"WARNING")});
-var self=this;
-var _214=function(name){
-return function(){
-self.logger[name].apply(self.logger,arguments);
-};
-};
-this.log=_214("log");
-this.logError=_214("error");
-this.logDebug=_214("debug");
-this.logFatal=_214("fatal");
-this.logWarning=_214("warning");
-this.logger=new _212();
-this.logger.useNativeConsole=true;
-this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
-m.nameFunctions(this);
-};
-if(typeof (printfire)=="undefined"&&typeof (document)!="undefined"&&document.createEvent&&typeof (dispatchEvent)!="undefined"){
-printfire=function(){
-printfire.args=arguments;
-var ev=document.createEvent("Events");
-ev.initEvent("printfire",false,true);
-dispatchEvent(ev);
-};
-}
-MochiKit.Logging.__new__();
-MochiKit.Base._exportSymbols(this,MochiKit.Logging);
-if(typeof (dojo)!="undefined"){
-dojo.provide("MochiKit.DateTime");
-}
-if(typeof (MochiKit)=="undefined"){
-MochiKit={};
-}
-if(typeof (MochiKit.DateTime)=="undefined"){
-MochiKit.DateTime={};
-}
-MochiKit.DateTime.NAME="MochiKit.DateTime";
-MochiKit.DateTime.VERSION="1.3.1";
-MochiKit.DateTime.__repr__=function(){
-return "["+this.NAME+" "+this.VERSION+"]";
-};
-MochiKit.DateTime.toString=function(){
-return this.__repr__();
-};
-MochiKit.DateTime.isoDate=function(str){
-str=str+"";
-if(typeof (str)!="string"||str.length===0){
-return null;
-}
-var iso=str.split("-");
-if(iso.length===0){
-return null;
-}
-return new Date(iso[0],iso[1]-1,iso[2]);
-};
-MochiKit.DateTime._isoRegexp=/(\d{4,})(?:-(\d{1,2})(?:-(\d{1,2})(?:[T ](\d{1,2}):(\d{1,2})(?::(\d{1,2})(?:\.(\d+))?)?(?:(Z)|([+-])(\d{1,2})(?::(\d{1,2}))?)?)?)?)?/;
-MochiKit.DateTime.isoTimestamp=function(str){
-str=str+"";
-if(typeof (str)!="string"||str.length===0){
-return null;
-}
-var res=str.match(MochiKit.DateTime._isoRegexp);
-if(typeof (res)=="undefined"||res===null){
-return null;
-}
-var year,month,day,hour,min,sec,msec;
-year=parseInt(res[1],10);
-if(typeof (res[2])=="undefined"||res[2]===""){
-return new Date(year);
-}
-month=parseInt(res[2],10)-1;
-day=parseInt(res[3],10);
-if(typeof (res[4])=="undefined"||res[4]===""){
-return new Date(year,month,day);
-}
-hour=parseInt(res[4],10);
-min=parseInt(res[5],10);
-sec=(typeof (res[6])!="undefined"&&res[6]!=="")?parseInt(res[6],10):0;
-if(typeof (res[7])!="undefined"&&res[7]!==""){
-msec=Math.round(1000*parseFloat("0."+res[7]));
-}else{
-msec=0;
-}
-if((typeof (res[8])=="undefined"||res[8]==="")&&(typeof (res[9])=="undefined"||res[9]==="")){
-return new Date(year,month,day,hour,min,sec,msec);
-}
-var ofs;
-if(typeof (res[9])!="undefined"&&res[9]!==""){
-ofs=parseInt(res[10],10)*3600000;
-if(typeof (res[11])!="undefined"&&res[11]!==""){
-ofs+=parseInt(res[11],10)*60000;
-}
-if(res[9]=="-"){
-ofs=-ofs;
-}
-}else{
-ofs=0;
-}
-return new Date(Date.UTC(year,month,day,hour,min,sec,msec)-ofs);
-};
-MochiKit.DateTime.toISOTime=function(date,_221){
-if(typeof (date)=="undefined"||date===null){
-return null;
-}
-var hh=date.getHours();
-var mm=date.getMinutes();
-var ss=date.getSeconds();
-var lst=[((_221&&(hh<10))?"0"+hh:hh),((mm<10)?"0"+mm:mm),((ss<10)?"0"+ss:ss)];
-return lst.join(":");
-};
-MochiKit.DateTime.toISOTimestamp=function(date,_225){
-if(typeof (date)=="undefined"||date===null){
-return null;
-}
-var sep=_225?"T":" ";
-var foot=_225?"Z":"";
-if(_225){
-date=new Date(date.getTime()+(date.getTimezoneOffset()*60000));
-}
-return MochiKit.DateTime.toISODate(date)+sep+MochiKit.DateTime.toISOTime(date,_225)+foot;
-};
-MochiKit.DateTime.toISODate=function(date){
-if(typeof (date)=="undefined"||date===null){
-return null;
-}
-var _228=MochiKit.DateTime._padTwo;
-return [date.getFullYear(),_228(date.getMonth()+1),_228(date.getDate())].join("-");
-};
-MochiKit.DateTime.americanDate=function(d){
-d=d+"";
-if(typeof (d)!="string"||d.length===0){
-return null;
-}
-var a=d.split("/");
-return new Date(a[2],a[0]-1,a[1]);
-};
-MochiKit.DateTime._padTwo=function(n){
-return (n>9)?n:"0"+n;
-};
-MochiKit.DateTime.toPaddedAmericanDate=function(d){
-if(typeof (d)=="undefined"||d===null){
-return null;
-}
-var _230=MochiKit.DateTime._padTwo;
-return [_230(d.getMonth()+1),_230(d.getDate()),d.getFullYear()].join("/");
-};
-MochiKit.DateTime.toAmericanDate=function(d){
-if(typeof (d)=="undefined"||d===null){
-return null;
-}
-return [d.getMonth()+1,d.getDate(),d.getFullYear()].join("/");
-};
-MochiKit.DateTime.EXPORT=["isoDate","isoTimestamp","toISOTime","toISOTimestamp","toISODate","americanDate","toPaddedAmericanDate","toAmericanDate"];
-MochiKit.DateTime.EXPORT_OK=[];
-MochiKit.DateTime.EXPORT_TAGS={":common":MochiKit.DateTime.EXPORT,":all":MochiKit.DateTime.EXPORT};
-MochiKit.DateTime.__new__=function(){
-var base=this.NAME+".";
-for(var k in this){
-var o=this[k];
-if(typeof (o)=="function"&&typeof (o.NAME)=="undefined"){
-try{
-o.NAME=base+k;
-}
-catch(e){
-}
-}
-}
-};
-MochiKit.DateTime.__new__();
-if(typeof (MochiKit.Base)!="undefined"){
-MochiKit.Base._exportSymbols(this,MochiKit.DateTime);
-}else{
-(function(_231,_232){
-if((typeof (JSAN)=="undefined"&&typeof (dojo)=="undefined")||(typeof (MochiKit.__compat__)=="boolean"&&MochiKit.__compat__)){
-var all=_232.EXPORT_TAGS[":all"];
-for(var i=0;i<all.length;i++){
-_231[all[i]]=_232[all[i]];
-}
-}
-})(this,MochiKit.DateTime);
-}
-if(typeof (dojo)!="undefined"){
-dojo.provide("MochiKit.Format");
-}
-if(typeof (MochiKit)=="undefined"){
-MochiKit={};
-}
-if(typeof (MochiKit.Format)=="undefined"){
-MochiKit.Format={};
-}
-MochiKit.Format.NAME="MochiKit.Format";
-MochiKit.Format.VERSION="1.3.1";
-MochiKit.Format.__repr__=function(){
-return "["+this.NAME+" "+this.VERSION+"]";
-};
-MochiKit.Format.toString=function(){
-return this.__repr__();
-};
-MochiKit.Format._numberFormatter=function(_233,_234,_235,_236,_237,_238,_239,_240,_241){
-return function(num){
-num=parseFloat(num);
-if(typeof (num)=="undefined"||num===null||isNaN(num)){
-return _233;
-}
-var _242=_234;
-var _243=_235;
-if(num<0){
-num=-num;
-}else{
-_242=_242.replace(/-/,"");
-}
-var me=arguments.callee;
-var fmt=MochiKit.Format.formatLocale(_236);
-if(_237){
-num=num*100;
-_243=fmt.percent+_243;
-}
-num=MochiKit.Format.roundToFixed(num,_238);
-var _245=num.split(/\./);
-var _246=_245[0];
-var frac=(_245.length==1)?"":_245[1];
-var res="";
-while(_246.length<_239){
-_246="0"+_246;
-}
-if(_240){
-while(_246.length>_240){
-var i=_246.length-_240;
-res=fmt.separator+_246.substring(i,_246.length)+res;
-_246=_246.substring(0,i);
-}
-}
-res=_246+res;
-if(_238>0){
-while(frac.length<_241){
-frac=frac+"0";
-}
-res=res+fmt.decimal+frac;
-}
-return _242+res+_243;
-};
-};
-MochiKit.Format.numberFormatter=function(_248,_249,_250){
-if(typeof (_249)=="undefined"){
-_249="";
-}
-var _251=_248.match(/((?:[0#]+,)?[0#]+)(?:\.([0#]+))?(%)?/);
-if(!_251){
-throw TypeError("Invalid pattern");
-}
-var _252=_248.substr(0,_251.index);
-var _253=_248.substr(_251.index+_251[0].length);
-if(_252.search(/-/)==-1){
-_252=_252+"-";
-}
-var _254=_251[1];
-var frac=(typeof (_251[2])=="string"&&_251[2]!="")?_251[2]:"";
-var _255=(typeof (_251[3])=="string"&&_251[3]!="");
-var tmp=_254.split(/,/);
-var _257;
-if(typeof (_250)=="undefined"){
-_250="default";
-}
-if(tmp.length==1){
-_257=null;
-}else{
-_257=tmp[1].length;
-}
-var _258=_254.length-_254.replace(/0/g,"").length;
-var _259=frac.length-frac.replace(/0/g,"").length;
-var _260=frac.length;
-var rval=MochiKit.Format._numberFormatter(_249,_252,_253,_250,_255,_260,_258,_257,_259);
-var m=MochiKit.Base;
-if(m){
-var fn=arguments.callee;
-var args=m.concat(arguments);
-rval.repr=function(){
-return [self.NAME,"(",map(m.repr,args).join(", "),")"].join("");
-};
-}
-return rval;
-};
-MochiKit.Format.formatLocale=function(_262){
-if(typeof (_262)=="undefined"||_262===null){
-_262="default";
-}
-if(typeof (_262)=="string"){
-var rval=MochiKit.Format.LOCALE[_262];
-if(typeof (rval)=="string"){
-rval=arguments.callee(rval);
-MochiKit.Format.LOCALE[_262]=rval;
-}
-return rval;
-}else{
-return _262;
-}
-};
-MochiKit.Format.twoDigitAverage=function(_263,_264){
-if(_264){
-var res=_263/_264;
-if(!isNaN(res)){
-return MochiKit.Format.twoDigitFloat(_263/_264);
-}
-}
-return "0";
-};
-MochiKit.Format.twoDigitFloat=function(_265){
-var sign=(_265<0?"-":"");
-var s=Math.floor(Math.abs(_265)*100).toString();
-if(s=="0"){
-return s;
-}
-if(s.length<3){
-while(s.charAt(s.length-1)=="0"){
-s=s.substring(0,s.length-1);
-}
-return sign+"0."+s;
-}
-var head=sign+s.substring(0,s.length-2);
-var tail=s.substring(s.length-2,s.length);
-if(tail=="00"){
-return head;
-}else{
-if(tail.charAt(1)=="0"){
-return head+"."+tail.charAt(0);
-}else{
-return head+"."+tail;
-}
-}
-};
-MochiKit.Format.lstrip=function(str,_270){
-str=str+"";
-if(typeof (str)!="string"){
-return null;
-}
-if(!_270){
-return str.replace(/^\s+/,"");
-}else{
-return str.replace(new RegExp("^["+_270+"]+"),"");
-}
-};
-MochiKit.Format.rstrip=function(str,_271){
-str=str+"";
-if(typeof (str)!="string"){
-return null;
-}
-if(!_271){
-return str.replace(/\s+$/,"");
-}else{
-return str.replace(new RegExp("["+_271+"]+$"),"");
-}
-};
-MochiKit.Format.strip=function(str,_272){
-var self=MochiKit.Format;
-return self.rstrip(self.lstrip(str,_272),_272);
-};
-MochiKit.Format.truncToFixed=function(_273,_274){
-_273=Math.floor(_273*Math.pow(10,_274));
-var res=(_273*Math.pow(10,-_274)).toFixed(_274);
-if(res.charAt(0)=="."){
-res="0"+res;
-}
-return res;
-};
-MochiKit.Format.roundToFixed=function(_275,_276){
-return MochiKit.Format.truncToFixed(_275+0.5*Math.pow(10,-_276),_276);
-};
-MochiKit.Format.percentFormat=function(_277){
-return MochiKit.Format.twoDigitFloat(100*_277)+"%";
-};
-MochiKit.Format.EXPORT=["truncToFixed","roundToFixed","numberFormatter","formatLocale","twoDigitAverage","twoDigitFloat","percentFormat","lstrip","rstrip","strip"];
-MochiKit.Format.LOCALE={en_US:{separator:",",decimal:".",percent:"%"},de_DE:{separator:".",decimal:",",percent:"%"},fr_FR:{separator:" ",decimal:",",percent:"%"},"default":"en_US"};
-MochiKit.Format.EXPORT_OK=[];
-MochiKit.Format.EXPORT_TAGS={":all":MochiKit.Format.EXPORT,":common":MochiKit.Format.EXPORT};
-MochiKit.Format.__new__=function(){
-var base=this.NAME+".";
-var k,v,o;
-for(k in this.LOCALE){
-o=this.LOCALE[k];
-if(typeof (o)=="object"){
-o.repr=function(){
-return this.NAME;
-};
-o.NAME=base+"LOCALE."+k;
-}
-}
-for(k in this){
-o=this[k];
-if(typeof (o)=="function"&&typeof (o.NAME)=="undefined"){
-try{
-o.NAME=base+k;
-}
-catch(e){
-}
-}
-}
-};
-MochiKit.Format.__new__();
-if(typeof (MochiKit.Base)!="undefined"){
-MochiKit.Base._exportSymbols(this,MochiKit.Format);
-}else{
-(function(_278,_279){
-if((typeof (JSAN)=="undefined"&&typeof (dojo)=="undefined")||(typeof (MochiKit.__compat__)=="boolean"&&MochiKit.__compat__)){
-var all=_279.EXPORT_TAGS[":all"];
-for(var i=0;i<all.length;i++){
-_278[all[i]]=_279[all[i]];
-}
-}
-})(this,MochiKit.Format);
-}
-if(typeof (dojo)!="undefined"){
-dojo.provide("MochiKit.Async");
-dojo.require("MochiKit.Base");
-}
-if(typeof (JSAN)!="undefined"){
-JSAN.use("MochiKit.Base",[]);
-}
-try{
-if(typeof (MochiKit.Base)=="undefined"){
-throw "";
-}
-}
-catch(e){
-throw "MochiKit.Async depends on MochiKit.Base!";
-}
-if(typeof (MochiKit.Async)=="undefined"){
-MochiKit.Async={};
-}
-MochiKit.Async.NAME="MochiKit.Async";
-MochiKit.Async.VERSION="1.3.1";
-MochiKit.Async.__repr__=function(){
-return "["+this.NAME+" "+this.VERSION+"]";
-};
-MochiKit.Async.toString=function(){
-return this.__repr__();
-};
-MochiKit.Async.Deferred=function(_280){
-this.chain=[];
-this.id=this._nextId();
-this.fired=-1;
-this.paused=0;
-this.results=[null,null];
-this.canceller=_280;
-this.silentlyCancelled=false;
-this.chained=false;
-};
-MochiKit.Async.Deferred.prototype={repr:function(){
-var _281;
-if(this.fired==-1){
-_281="unfired";
-}else{
-if(this.fired===0){
-_281="success";
-}else{
-_281="error";
-}
-}
-return "Deferred("+this.id+", "+_281+")";
-},toString:MochiKit.Base.forwardCall("repr"),_nextId:MochiKit.Base.counter(),cancel:function(){
-var self=MochiKit.Async;
-if(this.fired==-1){
-if(this.canceller){
-this.canceller(this);
-}else{
-this.silentlyCancelled=true;
-}
-if(this.fired==-1){
-this.errback(new self.CancelledError(this));
-}
-}else{
-if((this.fired===0)&&(this.results[0] instanceof self.Deferred)){
-this.results[0].cancel();
-}
-}
-},_pause:function(){
-this.paused++;
-},_unpause:function(){
-this.paused--;
-if((this.paused===0)&&(this.fired>=0)){
-this._fire();
-}
-},_continue:function(res){
-this._resback(res);
-this._unpause();
-},_resback:function(res){
-this.fired=((res instanceof Error)?1:0);
-this.results[this.fired]=res;
-this._fire();
-},_check:function(){
-if(this.fired!=-1){
-if(!this.silentlyCancelled){
-throw new MochiKit.Async.AlreadyCalledError(this);
-}
-this.silentlyCancelled=false;
-return;
-}
-},callback:function(res){
-this._check();
-if(res instanceof MochiKit.Async.Deferred){
-throw new Error("Deferred instances can only be chained if they are the result of a callback");
-}
-this._resback(res);
-},errback:function(res){
-this._check();
-var self=MochiKit.Async;
-if(res instanceof self.Deferred){
-throw new Error("Deferred instances can only be chained if they are the result of a callback");
-}
-if(!(res instanceof Error)){
-res=new self.GenericError(res);
-}
-this._resback(res);
-},addBoth:function(fn){
-if(arguments.length>1){
-fn=MochiKit.Base.partial.apply(null,arguments);
-}
-return this.addCallbacks(fn,fn);
-},addCallback:function(fn){
-if(arguments.length>1){
-fn=MochiKit.Base.partial.apply(null,arguments);
-}
-return this.addCallbacks(fn,null);
-},addErrback:function(fn){
-if(arguments.length>1){
-fn=MochiKit.Base.partial.apply(null,arguments);
-}
-return this.addCallbacks(null,fn);
-},addCallbacks:function(cb,eb){
-if(this.chained){
-throw new Error("Chained Deferreds can not be re-used");
-}
-this.chain.push([cb,eb]);
-if(this.fired>=0){
-this._fire();
-}
-return this;
-},_fire:function(){
-var _284=this.chain;
-var _285=this.fired;
-var res=this.results[_285];
-var self=this;
-var cb=null;
-while(_284.length>0&&this.paused===0){
-var pair=_284.shift();
-var f=pair[_285];
-if(f===null){
-continue;
-}
-try{
-res=f(res);
-_285=((res instanceof Error)?1:0);
-if(res instanceof MochiKit.Async.Deferred){
-cb=function(res){
-self._continue(res);
-};
-this._pause();
-}
-}
-catch(err){
-_285=1;
-if(!(err instanceof Error)){
-err=new MochiKit.Async.GenericError(err);
-}
-res=err;
-}
-}
-this.fired=_285;
-this.results[_285]=res;
-if(cb&&this.paused){
-res.addBoth(cb);
-res.chained=true;
-}
-}};
-MochiKit.Base.update(MochiKit.Async,{evalJSONRequest:function(){
-return eval("("+arguments[0].responseText+")");
-},succeed:function(_287){
-var d=new MochiKit.Async.Deferred();
-d.callback.apply(d,arguments);
-return d;
-},fail:function(_288){
-var d=new MochiKit.Async.Deferred();
-d.errback.apply(d,arguments);
-return d;
-},getXMLHttpRequest:function(){
-var self=arguments.callee;
-if(!self.XMLHttpRequest){
-var _289=[function(){
-return new XMLHttpRequest();
-},function(){
-return new ActiveXObject("Msxml2.XMLHTTP");
-},function(){
-return new ActiveXObject("Microsoft.XMLHTTP");
-},function(){
-return new ActiveXObject("Msxml2.XMLHTTP.4.0");
-},function(){
-throw new MochiKit.Async.BrowserComplianceError("Browser does not support XMLHttpRequest");
-}];
-for(var i=0;i<_289.length;i++){
-var func=_289[i];
-try{
-self.XMLHttpRequest=func;
-return func();
-}
-catch(e){
-}
-}
-}
-return self.XMLHttpRequest();
-},_nothing:function(){
-},_xhr_onreadystatechange:function(d){
-if(this.readyState==4){
-try{
-this.onreadystatechange=null;
-}
-catch(e){
-try{
-this.onreadystatechange=MochiKit.Async._nothing;
-}
-catch(e){
-}
-}
-var _290=null;
-try{
-_290=this.status;
-if(!_290&&MochiKit.Base.isNotEmpty(this.responseText)){
-_290=304;
-}
-}
-catch(e){
-}
-if(_290==200||_290==304){
-d.callback(this);
-}else{
-var err=new MochiKit.Async.XMLHttpRequestError(this,"Request failed");
-if(err.number){
-d.errback(err);
-}else{
-d.errback(err);
-}
-}
-}
-},_xhr_canceller:function(req){
-try{
-req.onreadystatechange=null;
-}
-catch(e){
-try{
-req.onreadystatechange=MochiKit.Async._nothing;
-}
-catch(e){
-}
-}
-req.abort();
-},sendXMLHttpRequest:function(req,_293){
-if(typeof (_293)=="undefined"||_293===null){
-_293="";
-}
-var m=MochiKit.Base;
-var self=MochiKit.Async;
-var d=new self.Deferred(m.partial(self._xhr_canceller,req));
-try{
-req.onreadystatechange=m.bind(self._xhr_onreadystatechange,req,d);
-req.send(_293);
-}
-catch(e){
-try{
-req.onreadystatechange=null;
-}
-catch(ignore){
-}
-d.errback(e);
-}
-return d;
-},doSimpleXMLHttpRequest:function(url){
-var self=MochiKit.Async;
-var req=self.getXMLHttpRequest();
-if(arguments.length>1){
-var m=MochiKit.Base;
-var qs=m.queryString.apply(null,m.extend(null,arguments,1));
-if(qs){
-url+="?"+qs;
-}
-}
-req.open("GET",url,true);
-return self.sendXMLHttpRequest(req);
-},loadJSONDoc:function(url){
-var self=MochiKit.Async;
-var d=self.doSimpleXMLHttpRequest.apply(self,arguments);
-d=d.addCallback(self.evalJSONRequest);
-return d;
-},wait:function(_296,_297){
-var d=new MochiKit.Async.Deferred();
-var m=MochiKit.Base;
-if(typeof (_297)!="undefined"){
-d.addCallback(function(){
-return _297;
-});
-}
-var _298=setTimeout(m.bind("callback",d),Math.floor(_296*1000));
-d.canceller=function(){
-try{
-clearTimeout(_298);
-}
-catch(e){
-}
-};
-return d;
-},callLater:function(_299,func){
-var m=MochiKit.Base;
-var _300=m.partial.apply(m,m.extend(null,arguments,1));
-return MochiKit.Async.wait(_299).addCallback(function(res){
-return _300();
-});
-}});
-MochiKit.Async.DeferredLock=function(){
-this.waiting=[];
-this.locked=false;
-this.id=this._nextId();
-};
-MochiKit.Async.DeferredLock.prototype={__class__:MochiKit.Async.DeferredLock,acquire:function(){
-d=new MochiKit.Async.Deferred();
-if(this.locked){
-this.waiting.push(d);
-}else{
-this.locked=true;
-d.callback(this);
-}
-return d;
-},release:function(){
-if(!this.locked){
-throw TypeError("Tried to release an unlocked DeferredLock");
-}
-this.locked=false;
-if(this.waiting.length>0){
-this.locked=true;
-this.waiting.shift().callback(this);
-}
-},_nextId:MochiKit.Base.counter(),repr:function(){
-var _301;
-if(this.locked){
-_301="locked, "+this.waiting.length+" waiting";
-}else{
-_301="unlocked";
-}
-return "DeferredLock("+this.id+", "+_301+")";
-},toString:MochiKit.Base.forwardCall("repr")};
-MochiKit.Async.DeferredList=function(list,_303,_304,_305,_306){
-this.list=list;
-this.resultList=new Array(this.list.length);
-this.chain=[];
-this.id=this._nextId();
-this.fired=-1;
-this.paused=0;
-this.results=[null,null];
-this.canceller=_306;
-this.silentlyCancelled=false;
-if(this.list.length===0&&!_303){
-this.callback(this.resultList);
-}
-this.finishedCount=0;
-this.fireOnOneCallback=_303;
-this.fireOnOneErrback=_304;
-this.consumeErrors=_305;
-var _307=0;
-MochiKit.Base.map(MochiKit.Base.bind(function(d){
-d.addCallback(MochiKit.Base.bind(this._cbDeferred,this),_307,true);
-d.addErrback(MochiKit.Base.bind(this._cbDeferred,this),_307,false);
-_307+=1;
-},this),this.list);
-};
-MochiKit.Base.update(MochiKit.Async.DeferredList.prototype,MochiKit.Async.Deferred.prototype);
-MochiKit.Base.update(MochiKit.Async.DeferredList.prototype,{_cbDeferred:function(_308,_309,_310){
-this.resultList[_308]=[_309,_310];
-this.finishedCount+=1;
-if(this.fired!==0){
-if(_309&&this.fireOnOneCallback){
-this.callback([_308,_310]);
-}else{
-if(!_309&&this.fireOnOneErrback){
-this.errback(_310);
-}else{
-if(this.finishedCount==this.list.length){
-this.callback(this.resultList);
-}
-}
-}
-}
-if(!_309&&this.consumeErrors){
-_310=null;
-}
-return _310;
-}});
-MochiKit.Async.gatherResults=function(_311){
-var d=new MochiKit.Async.DeferredList(_311,false,true,false);
-d.addCallback(function(_312){
-var ret=[];
-for(var i=0;i<_312.length;i++){
-ret.push(_312[i][1]);
-}
-return ret;
-});
-return d;
-};
-MochiKit.Async.maybeDeferred=function(func){
-var self=MochiKit.Async;
-var _313;
-try{
-var r=func.apply(null,MochiKit.Base.extend([],arguments,1));
-if(r instanceof self.Deferred){
-_313=r;
-}else{
-if(r instanceof Error){
-_313=self.fail(r);
-}else{
-_313=self.succeed(r);
-}
-}
-}
-catch(e){
-_313=self.fail(e);
-}
-return _313;
-};
-MochiKit.Async.EXPORT=["AlreadyCalledError","CancelledError","BrowserComplianceError","GenericError","XMLHttpRequestError","Deferred","succeed","fail","getXMLHttpRequest","doSimpleXMLHttpRequest","loadJSONDoc","wait","callLater","sendXMLHttpRequest","DeferredLock","DeferredList","gatherResults","maybeDeferred"];
-MochiKit.Async.EXPORT_OK=["evalJSONRequest"];
-MochiKit.Async.__new__=function(){
-var m=MochiKit.Base;
-var ne=m.partial(m._newNamedError,this);
-ne("AlreadyCalledError",function(_316){
-this.deferred=_316;
-});
-ne("CancelledError",function(_317){
-this.deferred=_317;
-});
-ne("BrowserComplianceError",function(msg){
-this.message=msg;
-});
-ne("GenericError",function(msg){
-this.message=msg;
-});
-ne("XMLHttpRequestError",function(req,msg){
-this.req=req;
-this.message=msg;
-try{
-this.number=req.status;
-}
-catch(e){
-}
-});
-this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
-m.nameFunctions(this);
-};
-MochiKit.Async.__new__();
-MochiKit.Base._exportSymbols(this,MochiKit.Async);
-if(typeof (dojo)!="undefined"){
-dojo.provide("MochiKit.DOM");
-dojo.require("MochiKit.Iter");
-}
-if(typeof (JSAN)!="undefined"){
-JSAN.use("MochiKit.Iter",[]);
-}
-try{
-if(typeof (MochiKit.Iter)=="undefined"){
-throw "";
-}
-}
-catch(e){
-throw "MochiKit.DOM depends on MochiKit.Iter!";
-}
-if(typeof (MochiKit.DOM)=="undefined"){
-MochiKit.DOM={};
-}
-MochiKit.DOM.NAME="MochiKit.DOM";
-MochiKit.DOM.VERSION="1.3.1";
-MochiKit.DOM.__repr__=function(){
-return "["+this.NAME+" "+this.VERSION+"]";
-};
-MochiKit.DOM.toString=function(){
-return this.__repr__();
-};
-MochiKit.DOM.EXPORT=["formContents","currentWindow","currentDocument","withWindow","withDocument","registerDOMConverter","coerceToDOM","createDOM","createDOMFunc","getNodeAttribute","setNodeAttribute","updateNodeAttributes","appendChildNodes","replaceChildNodes","removeElement","swapDOM","BUTTON","TT","PRE","H1","H2","H3","BR","CANVAS","HR","LABEL","TEXTAREA","FORM","STRONG","SELECT","OPTION","OPTGROUP","LEGEND","FIELDSET","P","UL","OL","LI","TD","TR","THEAD","TBODY","TFOOT","TABLE","TH","INPUT","SPAN","A","DIV","IMG","getElement","$","computedStyle","getElementsByTagAndClassName","addToCallStack","addLoadEvent","focusOnLoad","setElementClass","toggleElementClass","addElementClass","removeElementClass","swapElementClass","hasElementClass","escapeHTML","toHTML","emitHTML","setDisplayForElement","hideElement","showElement","scrapeText","elementDimensions","elementPosition","setElementDimensions","setElementPosition","getViewportDimensions","setOpacity"];
-MochiKit.DOM.EXPORT_OK=["domConverters"];
-MochiKit.DOM.Dimensions=function(w,h){
-this.w=w;
-this.h=h;
-};
-MochiKit.DOM.Dimensions.prototype.repr=function(){
-var repr=MochiKit.Base.repr;
-return "{w: "+repr(this.w)+", h: "+repr(this.h)+"}";
-};
-MochiKit.DOM.Coordinates=function(x,y){
-this.x=x;
-this.y=y;
-};
-MochiKit.DOM.Coordinates.prototype.repr=function(){
-var repr=MochiKit.Base.repr;
-return "{x: "+repr(this.x)+", y: "+repr(this.y)+"}";
-};
-MochiKit.DOM.Coordinates.prototype.toString=function(){
-return this.repr();
-};
-MochiKit.Base.update(MochiKit.DOM,{setOpacity:function(elem,o){
-elem=MochiKit.DOM.getElement(elem);
-MochiKit.DOM.updateNodeAttributes(elem,{"style":{"opacity":o,"-moz-opacity":o,"-khtml-opacity":o,"filter":" alpha(opacity="+(o*100)+")"}});
-},getViewportDimensions:function(){
-var d=new MochiKit.DOM.Dimensions();
-var w=MochiKit.DOM._window;
-var b=MochiKit.DOM._document.body;
-if(w.innerWidth){
-d.w=w.innerWidth;
-d.h=w.innerHeight;
-}else{
-if(b.parentElement.clientWidth){
-d.w=b.parentElement.clientWidth;
-d.h=b.parentElement.clientHeight;
-}else{
-if(b&&b.clientWidth){
-d.w=b.clientWidth;
-d.h=b.clientHeight;
-}
-}
-}
-return d;
-},elementDimensions:function(elem){
-var self=MochiKit.DOM;
-if(typeof (elem.w)=="number"||typeof (elem.h)=="number"){
-return new self.Dimensions(elem.w||0,elem.h||0);
-}
-elem=self.getElement(elem);
-if(!elem){
-return undefined;
-}
-if(self.computedStyle(elem,"display")!="none"){
-return new self.Dimensions(elem.offsetWidth||0,elem.offsetHeight||0);
-}
-var s=elem.style;
-var _322=s.visibility;
-var _323=s.position;
-s.visibility="hidden";
-s.position="absolute";
-s.display="";
-var _324=elem.offsetWidth;
-var _325=elem.offsetHeight;
-s.display="none";
-s.position=_323;
-s.visibility=_322;
-return new self.Dimensions(_324,_325);
-},elementPosition:function(elem,_326){
-var self=MochiKit.DOM;
-elem=self.getElement(elem);
-if(!elem){
-return undefined;
-}
-var c=new self.Coordinates(0,0);
-if(elem.x&&elem.y){
-c.x+=elem.x||0;
-c.y+=elem.y||0;
-return c;
-}else{
-if(elem.parentNode===null||self.computedStyle(elem,"display")=="none"){
-return undefined;
-}
-}
-var box=null;
-var _329=null;
-var d=MochiKit.DOM._document;
-var de=d.documentElement;
-var b=d.body;
-if(elem.getBoundingClientRect){
-box=elem.getBoundingClientRect();
-c.x+=box.left+(de.scrollLeft||b.scrollLeft)-(de.clientLeft||b.clientLeft);
-c.y+=box.top+(de.scrollTop||b.scrollTop)-(de.clientTop||b.clientTop);
-}else{
-if(d.getBoxObjectFor){
-box=d.getBoxObjectFor(elem);
-c.x+=box.x;
-c.y+=box.y;
-}else{
-if(elem.offsetParent){
-c.x+=elem.offsetLeft;
-c.y+=elem.offsetTop;
-_329=elem.offsetParent;
-if(_329!=elem){
-while(_329){
-c.x+=_329.offsetLeft;
-c.y+=_329.offsetTop;
-_329=_329.offsetParent;
-}
-}
-var ua=navigator.userAgent.toLowerCase();
-if((typeof (opera)!="undefined"&&parseFloat(opera.version())<9)||(ua.indexOf("safari")!=-1&&self.computedStyle(elem,"position")=="absolute")){
-c.x-=b.offsetLeft;
-c.y-=b.offsetTop;
-}
-}
-}
-}
-if(typeof (_326)!="undefined"){
-_326=arguments.callee(_326);
-if(_326){
-c.x-=(_326.x||0);
-c.y-=(_326.y||0);
-}
-}
-if(elem.parentNode){
-_329=elem.parentNode;
-}else{
-_329=null;
-}
-while(_329&&_329.tagName!="BODY"&&_329.tagName!="HTML"){
-c.x-=_329.scrollLeft;
-c.y-=_329.scrollTop;
-if(_329.parentNode){
-_329=_329.parentNode;
-}else{
-_329=null;
-}
-}
-return c;
-},setElementDimensions:function(elem,_332,_333){
-elem=MochiKit.DOM.getElement(elem);
-if(typeof (_333)=="undefined"){
-_333="px";
-}
-MochiKit.DOM.updateNodeAttributes(elem,{"style":{"width":_332.w+_333,"height":_332.h+_333}});
-},setElementPosition:function(elem,_334,_335){
-elem=MochiKit.DOM.getElement(elem);
-if(typeof (_335)=="undefined"){
-_335="px";
-}
-MochiKit.DOM.updateNodeAttributes(elem,{"style":{"left":_334.x+_335,"top":_334.y+_335}});
-},currentWindow:function(){
-return MochiKit.DOM._window;
-},currentDocument:function(){
-return MochiKit.DOM._document;
-},withWindow:function(win,func){
-var self=MochiKit.DOM;
-var _337=self._document;
-var _338=self._win;
-var rval;
-try{
-self._window=win;
-self._document=win.document;
-rval=func();
-}
-catch(e){
-self._window=_338;
-self._document=_337;
-throw e;
-}
-self._window=_338;
-self._document=_337;
-return rval;
-},formContents:function(elem){
-var _339=[];
-var _340=[];
-var m=MochiKit.Base;
-var self=MochiKit.DOM;
-if(typeof (elem)=="undefined"||elem===null){
-elem=self._document;
-}else{
-elem=self.getElement(elem);
-}
-m.nodeWalk(elem,function(elem){
-var name=elem.name;
-if(m.isNotEmpty(name)){
-var _341=elem.nodeName;
-if(_341=="INPUT"&&(elem.type=="radio"||elem.type=="checkbox")&&!elem.checked){
-return null;
-}
-if(_341=="SELECT"){
-if(elem.selectedIndex>=0){
-var opt=elem.options[elem.selectedIndex];
-_339.push(name);
-_340.push((opt.value)?opt.value:opt.text);
-return null;
-}
-_339.push(name);
-_340.push("");
-return null;
-}
-if(_341=="FORM"||_341=="P"||_341=="SPAN"||_341=="DIV"){
-return elem.childNodes;
-}
-_339.push(name);
-_340.push(elem.value||"");
-return null;
-}
-return elem.childNodes;
-});
-return [_339,_340];
-},withDocument:function(doc,func){
-var self=MochiKit.DOM;
-var _344=self._document;
-var rval;
-try{
-self._document=doc;
-rval=func();
-}
-catch(e){
-self._document=_344;
-throw e;
-}
-self._document=_344;
-return rval;
-},registerDOMConverter:function(name,_345,wrap,_346){
-MochiKit.DOM.domConverters.register(name,_345,wrap,_346);
-},coerceToDOM:function(node,ctx){
-var im=MochiKit.Iter;
-var self=MochiKit.DOM;
-var iter=im.iter;
-var _350=im.repeat;
-var imap=im.imap;
-var _352=self.domConverters;
-var _353=self.coerceToDOM;
-var _354=MochiKit.Base.NotFound;
-while(true){
-if(typeof (node)=="undefined"||node===null){
-return null;
-}
-if(typeof (node.nodeType)!="undefined"&&node.nodeType>0){
-return node;
-}
-if(typeof (node)=="number"||typeof (node)=="boolean"){
-node=node.toString();
-}
-if(typeof (node)=="string"){
-return self._document.createTextNode(node);
-}
-if(typeof (node.toDOM)=="function"){
-node=node.toDOM(ctx);
-continue;
-}
-if(typeof (node)=="function"){
-node=node(ctx);
-continue;
-}
-var _355=null;
-try{
-_355=iter(node);
-}
-catch(e){
-}
-if(_355){
-return imap(_353,_355,_350(ctx));
-}
-try{
-node=_352.match(node,ctx);
-continue;
-}
-catch(e){
-if(e!=_354){
-throw e;
-}
-}
-return self._document.createTextNode(node.toString());
-}
-return undefined;
-},setNodeAttribute:function(node,attr,_357){
-var o={};
-o[attr]=_357;
-try{
-return MochiKit.DOM.updateNodeAttributes(node,o);
-}
-catch(e){
-}
-return null;
-},getNodeAttribute:function(node,attr){
-var self=MochiKit.DOM;
-var _358=self.attributeArray.renames[attr];
-node=self.getElement(node);
-try{
-if(_358){
-return node[_358];
-}
-return node.getAttribute(attr);
-}
-catch(e){
-}
-return null;
-},updateNodeAttributes:function(node,_359){
-var elem=node;
-var self=MochiKit.DOM;
-if(typeof (node)=="string"){
-elem=self.getElement(node);
-}
-if(_359){
-var _360=MochiKit.Base.updatetree;
-if(self.attributeArray.compliant){
-for(var k in _359){
-var v=_359[k];
-if(typeof (v)=="object"&&typeof (elem[k])=="object"){
-_360(elem[k],v);
-}else{
-if(k.substring(0,2)=="on"){
-if(typeof (v)=="string"){
-v=new Function(v);
-}
-elem[k]=v;
-}else{
-elem.setAttribute(k,v);
-}
-}
-}
-}else{
-var _361=self.attributeArray.renames;
-for(k in _359){
-v=_359[k];
-var _362=_361[k];
-if(k=="style"&&typeof (v)=="string"){
-elem.style.cssText=v;
-}else{
-if(typeof (_362)=="string"){
-elem[_362]=v;
-}else{
-if(typeof (elem[k])=="object"&&typeof (v)=="object"){
-_360(elem[k],v);
-}else{
-if(k.substring(0,2)=="on"){
-if(typeof (v)=="string"){
-v=new Function(v);
-}
-elem[k]=v;
-}else{
-elem.setAttribute(k,v);
-}
-}
-}
-}
-}
-}
-}
-return elem;
-},appendChildNodes:function(node){
-var elem=node;
-var self=MochiKit.DOM;
-if(typeof (node)=="string"){
-elem=self.getElement(node);
-}
-var _363=[self.coerceToDOM(MochiKit.Base.extend(null,arguments,1),elem)];
-var _364=MochiKit.Base.concat;
-while(_363.length){
-var n=_363.shift();
-if(typeof (n)=="undefined"||n===null){
-}else{
-if(typeof (n.nodeType)=="number"){
-elem.appendChild(n);
-}else{
-_363=_364(n,_363);
-}
-}
-}
-return elem;
-},replaceChildNodes:function(node){
-var elem=node;
-var self=MochiKit.DOM;
-if(typeof (node)=="string"){
-elem=self.getElement(node);
-arguments[0]=elem;
-}
-var _365;
-while((_365=elem.firstChild)){
-elem.removeChild(_365);
-}
-if(arguments.length<2){
-return elem;
-}else{
-return self.appendChildNodes.apply(this,arguments);
-}
-},createDOM:function(name,_366){
-var elem;
-var self=MochiKit.DOM;
-var m=MochiKit.Base;
-if(typeof (_366)=="string"||typeof (_366)=="number"){
-var args=m.extend([name,null],arguments,1);
-return arguments.callee.apply(this,args);
-}
-if(typeof (name)=="string"){
-if(_366&&"name" in _366&&!self.attributeArray.compliant){
-name=("<"+name+" name=\""+self.escapeHTML(_366.name)+"\">");
-}
-elem=self._document.createElement(name);
-}else{
-elem=name;
-}
-if(_366){
-self.updateNodeAttributes(elem,_366);
-}
-if(arguments.length<=2){
-return elem;
-}else{
-var args=m.extend([elem],arguments,2);
-return self.appendChildNodes.apply(this,args);
-}
-},createDOMFunc:function(){
-var m=MochiKit.Base;
-return m.partial.apply(this,m.extend([MochiKit.DOM.createDOM],arguments));
-},swapDOM:function(dest,src){
-var self=MochiKit.DOM;
-dest=self.getElement(dest);
-var _369=dest.parentNode;
-if(src){
-src=self.getElement(src);
-_369.replaceChild(src,dest);
-}else{
-_369.removeChild(dest);
-}
-return src;
-},getElement:function(id){
-var self=MochiKit.DOM;
-if(arguments.length==1){
-return ((typeof (id)=="string")?self._document.getElementById(id):id);
-}else{
-return MochiKit.Base.map(self.getElement,arguments);
-}
-},computedStyle:function(_371,_372,_373){
-if(arguments.length==2){
-_373=_372;
-}
-var self=MochiKit.DOM;
-var el=self.getElement(_371);
-var _375=self._document;
-if(!el||el==_375){
-return undefined;
-}
-if(el.currentStyle){
-return el.currentStyle[_372];
-}
-if(typeof (_375.defaultView)=="undefined"){
-return undefined;
-}
-if(_375.defaultView===null){
-return undefined;
-}
-var _376=_375.defaultView.getComputedStyle(el,null);
-if(typeof (_376)=="undefined"||_376===null){
-return undefined;
-}
-return _376.getPropertyValue(_373);
-},getElementsByTagAndClassName:function(_377,_378,_379){
-var self=MochiKit.DOM;
-if(typeof (_377)=="undefined"||_377===null){
-_377="*";
-}
-if(typeof (_379)=="undefined"||_379===null){
-_379=self._document;
-}
-_379=self.getElement(_379);
-var _380=(_379.getElementsByTagName(_377)||self._document.all);
-if(typeof (_378)=="undefined"||_378===null){
-return MochiKit.Base.extend(null,_380);
-}
-var _381=[];
-for(var i=0;i<_380.length;i++){
-var _382=_380[i];
-var _383=_382.className.split(" ");
-for(var j=0;j<_383.length;j++){
-if(_383[j]==_378){
-_381.push(_382);
-break;
-}
-}
-}
-return _381;
-},_newCallStack:function(path,once){
-var rval=function(){
-var _386=arguments.callee.callStack;
-for(var i=0;i<_386.length;i++){
-if(_386[i].apply(this,arguments)===false){
-break;
-}
-}
-if(once){
-try{
-this[path]=null;
-}
-catch(e){
-}
-}
-};
-rval.callStack=[];
-return rval;
-},addToCallStack:function(_387,path,func,once){
-var self=MochiKit.DOM;
-var _388=_387[path];
-var _389=_388;
-if(!(typeof (_388)=="function"&&typeof (_388.callStack)=="object"&&_388.callStack!==null)){
-_389=self._newCallStack(path,once);
-if(typeof (_388)=="function"){
-_389.callStack.push(_388);
-}
-_387[path]=_389;
-}
-_389.callStack.push(func);
-},addLoadEvent:function(func){
-var self=MochiKit.DOM;
-self.addToCallStack(self._window,"onload",func,true);
-},focusOnLoad:function(_390){
-var self=MochiKit.DOM;
-self.addLoadEvent(function(){
-_390=self.getElement(_390);
-if(_390){
-_390.focus();
-}
-});
-},setElementClass:function(_391,_392){
-var self=MochiKit.DOM;
-var obj=self.getElement(_391);
-if(self.attributeArray.compliant){
-obj.setAttribute("class",_392);
-}else{
-obj.setAttribute("className",_392);
-}
-},toggleElementClass:function(_393){
-var self=MochiKit.DOM;
-for(var i=1;i<arguments.length;i++){
-var obj=self.getElement(arguments[i]);
-if(!self.addElementClass(obj,_393)){
-self.removeElementClass(obj,_393);
-}
-}
-},addElementClass:function(_394,_395){
-var self=MochiKit.DOM;
-var obj=self.getElement(_394);
-var cls=obj.className;
-if(cls.length===0){
-self.setElementClass(obj,_395);
-return true;
-}
-if(cls==_395){
-return false;
-}
-var _397=obj.className.split(" ");
-for(var i=0;i<_397.length;i++){
-if(_397[i]==_395){
-return false;
-}
-}
-self.setElementClass(obj,cls+" "+_395);
-return true;
-},removeElementClass:function(_398,_399){
-var self=MochiKit.DOM;
-var obj=self.getElement(_398);
-var cls=obj.className;
-if(cls.length===0){
-return false;
-}
-if(cls==_399){
-self.setElementClass(obj,"");
-return true;
-}
-var _400=obj.className.split(" ");
-for(var i=0;i<_400.length;i++){
-if(_400[i]==_399){
-_400.splice(i,1);
-self.setElementClass(obj,_400.join(" "));
-return true;
-}
-}
-return false;
-},swapElementClass:function(_401,_402,_403){
-var obj=MochiKit.DOM.getElement(_401);
-var res=MochiKit.DOM.removeElementClass(obj,_402);
-if(res){
-MochiKit.DOM.addElementClass(obj,_403);
-}
-return res;
-},hasElementClass:function(_404,_405){
-var obj=MochiKit.DOM.getElement(_404);
-var _406=obj.className.split(" ");
-for(var i=1;i<arguments.length;i++){
-var good=false;
-for(var j=0;j<_406.length;j++){
-if(_406[j]==arguments[i]){
-good=true;
-break;
-}
-}
-if(!good){
-return false;
-}
-}
-return true;
-},escapeHTML:function(s){
-return s.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
-},toHTML:function(dom){
-return MochiKit.DOM.emitHTML(dom).join("");
-},emitHTML:function(dom,lst){
-if(typeof (lst)=="undefined"||lst===null){
-lst=[];
-}
-var _409=[dom];
-var self=MochiKit.DOM;
-var _410=self.escapeHTML;
-var _411=self.attributeArray;
-while(_409.length){
-dom=_409.pop();
-if(typeof (dom)=="string"){
-lst.push(dom);
-}else{
-if(dom.nodeType==1){
-lst.push("<"+dom.nodeName.toLowerCase());
-var _412=[];
-var _413=_411(dom);
-for(var i=0;i<_413.length;i++){
-var a=_413[i];
-_412.push([" ",a.name,"=\"",_410(a.value),"\""]);
-}
-_412.sort();
-for(i=0;i<_412.length;i++){
-var _414=_412[i];
-for(var j=0;j<_414.length;j++){
-lst.push(_414[j]);
-}
-}
-if(dom.hasChildNodes()){
-lst.push(">");
-_409.push("</"+dom.nodeName.toLowerCase()+">");
-var _415=dom.childNodes;
-for(i=_415.length-1;i>=0;i--){
-_409.push(_415[i]);
-}
-}else{
-lst.push("/>");
-}
-}else{
-if(dom.nodeType==3){
-lst.push(_410(dom.nodeValue));
-}
-}
-}
-}
-return lst;
-},setDisplayForElement:function(_416,_417){
-var m=MochiKit.Base;
-var _418=m.extend(null,arguments,1);
-MochiKit.Iter.forEach(m.filter(null,m.map(MochiKit.DOM.getElement,_418)),function(_417){
-_417.style.display=_416;
-});
-},scrapeText:function(node,_419){
-var rval=[];
-(function(node){
-var cn=node.childNodes;
-if(cn){
-for(var i=0;i<cn.length;i++){
-arguments.callee.call(this,cn[i]);
-}
-}
-var _421=node.nodeValue;
-if(typeof (_421)=="string"){
-rval.push(_421);
-}
-})(MochiKit.DOM.getElement(node));
-if(_419){
-return rval;
-}else{
-return rval.join("");
-}
-},__new__:function(win){
-var m=MochiKit.Base;
-this._document=document;
-this._window=win;
-this.domConverters=new m.AdapterRegistry();
-var _422=this._document.createElement("span");
-var _423;
-if(_422&&_422.attributes&&_422.attributes.length>0){
-var _424=m.filter;
-_423=function(node){
-return _424(_423.ignoreAttrFilter,node.attributes);
-};
-_423.ignoreAttr={};
-MochiKit.Iter.forEach(_422.attributes,function(a){
-_423.ignoreAttr[a.name]=a.value;
-});
-_423.ignoreAttrFilter=function(a){
-return (_423.ignoreAttr[a.name]!=a.value);
-};
-_423.compliant=false;
-_423.renames={"class":"className","checked":"defaultChecked","usemap":"useMap","for":"htmlFor"};
-}else{
-_423=function(node){
-return node.attributes;
-};
-_423.compliant=true;
-_423.renames={};
-}
-this.attributeArray=_423;
-var _425=this.createDOMFunc;
-this.UL=_425("ul");
-this.OL=_425("ol");
-this.LI=_425("li");
-this.TD=_425("td");
-this.TR=_425("tr");
-this.TBODY=_425("tbody");
-this.THEAD=_425("thead");
-this.TFOOT=_425("tfoot");
-this.TABLE=_425("table");
-this.TH=_425("th");
-this.INPUT=_425("input");
-this.SPAN=_425("span");
-this.A=_425("a");
-this.DIV=_425("div");
-this.IMG=_425("img");
-this.BUTTON=_425("button");
-this.TT=_425("tt");
-this.PRE=_425("pre");
-this.H1=_425("h1");
-this.H2=_425("h2");
-this.H3=_425("h3");
-this.BR=_425("br");
-this.HR=_425("hr");
-this.LABEL=_425("label");
-this.TEXTAREA=_425("textarea");
-this.FORM=_425("form");
-this.P=_425("p");
-this.SELECT=_425("select");
-this.OPTION=_425("option");
-this.OPTGROUP=_425("optgroup");
-this.LEGEND=_425("legend");
-this.FIELDSET=_425("fieldset");
-this.STRONG=_425("strong");
-this.CANVAS=_425("canvas");
-this.hideElement=m.partial(this.setDisplayForElement,"none");
-this.showElement=m.partial(this.setDisplayForElement,"block");
-this.removeElement=this.swapDOM;
-this.$=this.getElement;
-this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
-m.nameFunctions(this);
-}});
-MochiKit.DOM.__new__(((typeof (window)=="undefined")?this:window));
-if(!MochiKit.__compat__){
-withWindow=MochiKit.DOM.withWindow;
-withDocument=MochiKit.DOM.withDocument;
-}
-MochiKit.Base._exportSymbols(this,MochiKit.DOM);
-if(typeof (dojo)!="undefined"){
-dojo.provide("MochiKit.LoggingPane");
-dojo.require("MochiKit.Logging");
-dojo.require("MochiKit.Base");
-}
-if(typeof (JSAN)!="undefined"){
-JSAN.use("MochiKit.Logging",[]);
-JSAN.use("MochiKit.Base",[]);
-}
-try{
-if(typeof (MochiKit.Base)=="undefined"||typeof (MochiKit.Logging)=="undefined"){
-throw "";
-}
-}
-catch(e){
-throw "MochiKit.LoggingPane depends on MochiKit.Base and MochiKit.Logging!";
-}
-if(typeof (MochiKit.LoggingPane)=="undefined"){
-MochiKit.LoggingPane={};
-}
-MochiKit.LoggingPane.NAME="MochiKit.LoggingPane";
-MochiKit.LoggingPane.VERSION="1.3.1";
-MochiKit.LoggingPane.__repr__=function(){
-return "["+this.NAME+" "+this.VERSION+"]";
-};
-MochiKit.LoggingPane.toString=function(){
-return this.__repr__();
-};
-MochiKit.LoggingPane.createLoggingPane=function(_426){
-var m=MochiKit.LoggingPane;
-_426=!(!_426);
-if(m._loggingPane&&m._loggingPane.inline!=_426){
-m._loggingPane.closePane();
-m._loggingPane=null;
-}
-if(!m._loggingPane||m._loggingPane.closed){
-m._loggingPane=new m.LoggingPane(_426,MochiKit.Logging.logger);
-}
-return m._loggingPane;
-};
-MochiKit.LoggingPane.LoggingPane=function(_427,_428){
-if(typeof (_428)=="undefined"||_428===null){
-_428=MochiKit.Logging.logger;
-}
-this.logger=_428;
-var _429=MochiKit.Base.update;
-var _430=MochiKit.Base.updatetree;
-var bind=MochiKit.Base.bind;
-var _431=MochiKit.Base.clone;
-var win=window;
-var uid="_MochiKit_LoggingPane";
-if(typeof (MochiKit.DOM)!="undefined"){
-win=MochiKit.DOM.currentWindow();
-}
-if(!_427){
-var url=win.location.href.split("?")[0].replace(/[:\/.><&]/g,"_");
-var name=uid+"_"+url;
-var nwin=win.open("",name,"dependent,resizable,height=200");
-if(!nwin){
-alert("Not able to open debugging window due to pop-up blocking.");
-return undefined;
-}
-nwin.document.write("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" "+"\"http://www.w3.org/TR/html4/loose.dtd\">"+"<html><head><title>[MochiKit.LoggingPane]</title></head>"+"<body></body></html>");
-nwin.document.close();
-nwin.document.title+=" "+win.document.title;
-win=nwin;
-}
-var doc=win.document;
-this.doc=doc;
-var _434=doc.getElementById(uid);
-var _435=!!_434;
-if(_434&&typeof (_434.loggingPane)!="undefined"){
-_434.loggingPane.logger=this.logger;
-_434.loggingPane.buildAndApplyFilter();
-return _434.loggingPane;
-}
-if(_435){
-var _436;
-while((_436=_434.firstChild)){
-_434.removeChild(_436);
-}
-}else{
-_434=doc.createElement("div");
-_434.id=uid;
-}
-_434.loggingPane=this;
-var _437=doc.createElement("input");
-var _438=doc.createElement("input");
-var _439=doc.createElement("button");
-var _440=doc.createElement("button");
-var _441=doc.createElement("button");
-var _442=doc.createElement("button");
-var _443=doc.createElement("div");
-var _444=doc.createElement("div");
-var _445=uid+"_Listener";
-this.colorTable=_431(this.colorTable);
-var _446=[];
-var _447=null;
-var _448=function(msg){
-var _449=msg.level;
-if(typeof (_449)=="number"){
-_449=MochiKit.Logging.LogLevel[_449];
-}
-return _449;
-};
-var _450=function(msg){
-return msg.info.join(" ");
-};
-var _451=bind(function(msg){
-var _452=_448(msg);
-var text=_450(msg);
-var c=this.colorTable[_452];
-var p=doc.createElement("span");
-p.className="MochiKit-LogMessage MochiKit-LogLevel-"+_452;
-p.style.cssText="margin: 0px; white-space: -moz-pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; white-space: pre-line; word-wrap: break-word; wrap-option: emergency; color: "+c;
-p.appendChild(doc.createTextNode(_452+": "+text));
-_444.appendChild(p);
-_444.appendChild(doc.createElement("br"));
-if(_443.offsetHeight>_443.scrollHeight){
-_443.scrollTop=0;
-}else{
-_443.scrollTop=_443.scrollHeight;
-}
-},this);
-var _454=function(msg){
-_446[_446.length]=msg;
-_451(msg);
-};
-var _455=function(){
-var _456,infore;
-try{
-_456=new RegExp(_437.value);
-infore=new RegExp(_438.value);
-}
-catch(e){
-logDebug("Error in filter regex: "+e.message);
-return null;
-}
-return function(msg){
-return (_456.test(_448(msg))&&infore.test(_450(msg)));
-};
-};
-var _457=function(){
-while(_444.firstChild){
-_444.removeChild(_444.firstChild);
-}
-};
-var _458=function(){
-_446=[];
-_457();
-};
-var _459=bind(function(){
-if(this.closed){
-return;
-}
-this.closed=true;
-if(MochiKit.LoggingPane._loggingPane==this){
-MochiKit.LoggingPane._loggingPane=null;
-}
-this.logger.removeListener(_445);
-_434.loggingPane=null;
-if(_427){
-_434.parentNode.removeChild(_434);
-}else{
-this.win.close();
-}
-},this);
-var _460=function(){
-_457();
-for(var i=0;i<_446.length;i++){
-var msg=_446[i];
-if(_447===null||_447(msg)){
-_451(msg);
-}
-}
-};
-this.buildAndApplyFilter=function(){
-_447=_455();
-_460();
-this.logger.removeListener(_445);
-this.logger.addListener(_445,_447,_454);
-};
-var _461=bind(function(){
-_446=this.logger.getMessages();
-_460();
-},this);
-var _462=bind(function(_463){
-_463=_463||window.event;
-key=_463.which||_463.keyCode;
-if(key==13){
-this.buildAndApplyFilter();
-}
-},this);
-var _464="display: block; z-index: 1000; left: 0px; bottom: 0px; position: fixed; width: 100%; background-color: white; font: "+this.logFont;
-if(_427){
-_464+="; height: 10em; border-top: 2px solid black";
-}else{
-_464+="; height: 100%;";
-}
-_434.style.cssText=_464;
-if(!_435){
-doc.body.appendChild(_434);
-}
-_464={"cssText":"width: 33%; display: inline; font: "+this.logFont};
-_430(_437,{"value":"FATAL|ERROR|WARNING|INFO|DEBUG","onkeypress":_462,"style":_464});
-_434.appendChild(_437);
-_430(_438,{"value":".*","onkeypress":_462,"style":_464});
-_434.appendChild(_438);
-_464="width: 8%; display:inline; font: "+this.logFont;
-_439.appendChild(doc.createTextNode("Filter"));
-_439.onclick=bind("buildAndApplyFilter",this);
-_439.style.cssText=_464;
-_434.appendChild(_439);
-_440.appendChild(doc.createTextNode("Load"));
-_440.onclick=_461;
-_440.style.cssText=_464;
-_434.appendChild(_440);
-_441.appendChild(doc.createTextNode("Clear"));
-_441.onclick=_458;
-_441.style.cssText=_464;
-_434.appendChild(_441);
-_442.appendChild(doc.createTextNode("Close"));
-_442.onclick=_459;
-_442.style.cssText=_464;
-_434.appendChild(_442);
-_443.style.cssText="overflow: auto; width: 100%";
-_444.style.cssText="width: 100%; height: "+(_427?"8em":"100%");
-_443.appendChild(_444);
-_434.appendChild(_443);
-this.buildAndApplyFilter();
-_461();
-if(_427){
-this.win=undefined;
-}else{
-this.win=win;
-}
-this.inline=_427;
-this.closePane=_459;
-this.closed=false;
-return this;
-};
-MochiKit.LoggingPane.LoggingPane.prototype={"logFont":"8pt Verdana,sans-serif","colorTable":{"ERROR":"red","FATAL":"darkred","WARNING":"blue","INFO":"black","DEBUG":"green"}};
-MochiKit.LoggingPane.EXPORT_OK=["LoggingPane"];
-MochiKit.LoggingPane.EXPORT=["createLoggingPane"];
-MochiKit.LoggingPane.__new__=function(){
-this.EXPORT_TAGS={":common":this.EXPORT,":all":MochiKit.Base.concat(this.EXPORT,this.EXPORT_OK)};
-MochiKit.Base.nameFunctions(this);
-MochiKit.LoggingPane._loggingPane=null;
-};
-MochiKit.LoggingPane.__new__();
-MochiKit.Base._exportSymbols(this,MochiKit.LoggingPane);
-if(typeof (dojo)!="undefined"){
-dojo.provide("MochiKit.Color");
-dojo.require("MochiKit.Base");
-}
-if(typeof (JSAN)!="undefined"){
-JSAN.use("MochiKit.Base",[]);
-}
-try{
-if(typeof (MochiKit.Base)=="undefined"){
-throw "";
-}
-}
-catch(e){
-throw "MochiKit.Color depends on MochiKit.Base";
-}
-if(typeof (MochiKit.Color)=="undefined"){
-MochiKit.Color={};
-}
-MochiKit.Color.NAME="MochiKit.Color";
-MochiKit.Color.VERSION="1.3.1";
-MochiKit.Color.__repr__=function(){
-return "["+this.NAME+" "+this.VERSION+"]";
-};
-MochiKit.Color.toString=function(){
-return this.__repr__();
-};
-MochiKit.Color.Color=function(red,_466,blue,_468){
-if(typeof (_468)=="undefined"||_468===null){
-_468=1;
-}
-this.rgb={r:red,g:_466,b:blue,a:_468};
-};
-MochiKit.Color.Color.prototype={__class__:MochiKit.Color.Color,colorWithAlpha:function(_469){
-var rgb=this.rgb;
-var m=MochiKit.Color;
-return m.Color.fromRGB(rgb.r,rgb.g,rgb.b,_469);
-},colorWithHue:function(hue){
-var hsl=this.asHSL();
-hsl.h=hue;
-var m=MochiKit.Color;
-return m.Color.fromHSL(hsl);
-},colorWithSaturation:function(_473){
-var hsl=this.asHSL();
-hsl.s=_473;
-var m=MochiKit.Color;
-return m.Color.fromHSL(hsl);
-},colorWithLightness:function(_474){
-var hsl=this.asHSL();
-hsl.l=_474;
-var m=MochiKit.Color;
-return m.Color.fromHSL(hsl);
-},darkerColorWithLevel:function(_475){
-var hsl=this.asHSL();
-hsl.l=Math.max(hsl.l-_475,0);
-var m=MochiKit.Color;
-return m.Color.fromHSL(hsl);
-},lighterColorWithLevel:function(_476){
-var hsl=this.asHSL();
-hsl.l=Math.min(hsl.l+_476,1);
-var m=MochiKit.Color;
-return m.Color.fromHSL(hsl);
-},blendedColor:function(_477,_478){
-if(typeof (_478)=="undefined"||_478===null){
-_478=0.5;
-}
-var sf=1-_478;
-var s=this.rgb;
-var d=_477.rgb;
-var df=_478;
-return MochiKit.Color.Color.fromRGB((s.r*sf)+(d.r*df),(s.g*sf)+(d.g*df),(s.b*sf)+(d.b*df),(s.a*sf)+(d.a*df));
-},compareRGB:function(_481){
-var a=this.asRGB();
-var b=_481.asRGB();
-return MochiKit.Base.compare([a.r,a.g,a.b,a.a],[b.r,b.g,b.b,b.a]);
-},isLight:function(){
-return this.asHSL().b>0.5;
-},isDark:function(){
-return (!this.isLight());
-},toHSLString:function(){
-var c=this.asHSL();
-var ccc=MochiKit.Color.clampColorComponent;
-var rval=this._hslString;
-if(!rval){
-var mid=(ccc(c.h,360).toFixed(0)+","+ccc(c.s,100).toPrecision(4)+"%"+","+ccc(c.l,100).toPrecision(4)+"%");
-var a=c.a;
-if(a>=1){
-a=1;
-rval="hsl("+mid+")";
-}else{
-if(a<=0){
-a=0;
-}
-rval="hsla("+mid+","+a+")";
-}
-this._hslString=rval;
-}
-return rval;
-},toRGBString:function(){
-var c=this.rgb;
-var ccc=MochiKit.Color.clampColorComponent;
-var rval=this._rgbString;
-if(!rval){
-var mid=(ccc(c.r,255).toFixed(0)+","+ccc(c.g,255).toFixed(0)+","+ccc(c.b,255).toFixed(0));
-if(c.a!=1){
-rval="rgba("+mid+","+c.a+")";
-}else{
-rval="rgb("+mid+")";
-}
-this._rgbString=rval;
-}
-return rval;
-},asRGB:function(){
-return MochiKit.Base.clone(this.rgb);
-},toHexString:function(){
-var m=MochiKit.Color;
-var c=this.rgb;
-var ccc=MochiKit.Color.clampColorComponent;
-var rval=this._hexString;
-if(!rval){
-rval=("#"+m.toColorPart(ccc(c.r,255))+m.toColorPart(ccc(c.g,255))+m.toColorPart(ccc(c.b,255)));
-this._hexString=rval;
-}
-return rval;
-},asHSV:function(){
-var hsv=this.hsv;
-var c=this.rgb;
-if(typeof (hsv)=="undefined"||hsv===null){
-hsv=MochiKit.Color.rgbToHSV(this.rgb);
-this.hsv=hsv;
-}
-return MochiKit.Base.clone(hsv);
-},asHSL:function(){
-var hsl=this.hsl;
-var c=this.rgb;
-if(typeof (hsl)=="undefined"||hsl===null){
-hsl=MochiKit.Color.rgbToHSL(this.rgb);
-this.hsl=hsl;
-}
-return MochiKit.Base.clone(hsl);
-},toString:function(){
-return this.toRGBString();
-},repr:function(){
-var c=this.rgb;
-var col=[c.r,c.g,c.b,c.a];
-return this.__class__.NAME+"("+col.join(", ")+")";
-}};
-MochiKit.Base.update(MochiKit.Color.Color,{fromRGB:function(red,_486,blue,_487){
-var _488=MochiKit.Color.Color;
-if(arguments.length==1){
-var rgb=red;
-red=rgb.r;
-_486=rgb.g;
-blue=rgb.b;
-if(typeof (rgb.a)=="undefined"){
-_487=undefined;
-}else{
-_487=rgb.a;
-}
-}
-return new _488(red,_486,blue,_487);
-},fromHSL:function(hue,_489,_490,_491){
-var m=MochiKit.Color;
-return m.Color.fromRGB(m.hslToRGB.apply(m,arguments));
-},fromHSV:function(hue,_492,_493,_494){
-var m=MochiKit.Color;
-return m.Color.fromRGB(m.hsvToRGB.apply(m,arguments));
-},fromName:function(name){
-var _495=MochiKit.Color.Color;
-if(name.charAt(0)=="\""){
-name=name.substr(1,name.length-2);
-}
-var _496=_495._namedColors[name.toLowerCase()];
-if(typeof (_496)=="string"){
-return _495.fromHexString(_496);
-}else{
-if(name=="transparent"){
-return _495.transparentColor();
-}
-}
-return null;
-},fromString:function(_497){
-var self=MochiKit.Color.Color;
-var _498=_497.substr(0,3);
-if(_498=="rgb"){
-return self.fromRGBString(_497);
-}else{
-if(_498=="hsl"){
-return self.fromHSLString(_497);
-}else{
-if(_497.charAt(0)=="#"){
-return self.fromHexString(_497);
-}
-}
-}
-return self.fromName(_497);
-},fromHexString:function(_499){
-if(_499.charAt(0)=="#"){
-_499=_499.substring(1);
-}
-var _500=[];
-var i,hex;
-if(_499.length==3){
-for(i=0;i<3;i++){
-hex=_499.substr(i,1);
-_500.push(parseInt(hex+hex,16)/255);
-}
-}else{
-for(i=0;i<6;i+=2){
-hex=_499.substr(i,2);
-_500.push(parseInt(hex,16)/255);
-}
-}
-var _501=MochiKit.Color.Color;
-return _501.fromRGB.apply(_501,_500);
-},_fromColorString:function(pre,_503,_504,_505){
-if(_505.indexOf(pre)===0){
-_505=_505.substring(_505.indexOf("(",3)+1,_505.length-1);
-}
-var _506=_505.split(/\s*,\s*/);
-var _507=[];
-for(var i=0;i<_506.length;i++){
-var c=_506[i];
-var val;
-var _508=c.substring(c.length-3);
-if(c.charAt(c.length-1)=="%"){
-val=0.01*parseFloat(c.substring(0,c.length-1));
-}else{
-if(_508=="deg"){
-val=parseFloat(c)/360;
-}else{
-if(_508=="rad"){
-val=parseFloat(c)/(Math.PI*2);
-}else{
-val=_504[i]*parseFloat(c);
-}
-}
-}
-_507.push(val);
-}
-return this[_503].apply(this,_507);
-},fromComputedStyle:function(elem,_509,_510){
-var d=MochiKit.DOM;
-var cls=MochiKit.Color.Color;
-for(elem=d.getElement(elem);elem;elem=elem.parentNode){
-var _511=d.computedStyle.apply(d,arguments);
-if(!_511){
-continue;
-}
-var _512=cls.fromString(_511);
-if(!_512){
-break;
-}
-if(_512.asRGB().a>0){
-return _512;
-}
-}
-return null;
-},fromBackground:function(elem){
-var cls=MochiKit.Color.Color;
-return cls.fromComputedStyle(elem,"backgroundColor","background-color")||cls.whiteColor();
-},fromText:function(elem){
-var cls=MochiKit.Color.Color;
-return cls.fromComputedStyle(elem,"color","color")||cls.blackColor();
-},namedColors:function(){
-return MochiKit.Base.clone(MochiKit.Color.Color._namedColors);
-}});
-MochiKit.Base.update(MochiKit.Color,{clampColorComponent:function(v,_513){
-v*=_513;
-if(v<0){
-return 0;
-}else{
-if(v>_513){
-return _513;
-}else{
-return v;
-}
-}
-},_hslValue:function(n1,n2,hue){
-if(hue>6){
-hue-=6;
-}else{
-if(hue<0){
-hue+=6;
-}
-}
-var val;
-if(hue<1){
-val=n1+(n2-n1)*hue;
-}else{
-if(hue<3){
-val=n2;
-}else{
-if(hue<4){
-val=n1+(n2-n1)*(4-hue);
-}else{
-val=n1;
-}
-}
-}
-return val;
-},hsvToRGB:function(hue,_516,_517,_518){
-if(arguments.length==1){
-var hsv=hue;
-hue=hsv.h;
-_516=hsv.s;
-_517=hsv.v;
-_518=hsv.a;
-}
-var red;
-var _519;
-var blue;
-if(_516===0){
-red=0;
-_519=0;
-blue=0;
-}else{
-var i=Math.floor(hue*6);
-var f=(hue*6)-i;
-var p=_517*(1-_516);
-var q=_517*(1-(_516*f));
-var t=_517*(1-(_516*(1-f)));
-switch(i){
-case 1:
-red=q;
-_519=_517;
-blue=p;
-break;
-case 2:
-red=p;
-_519=_517;
-blue=t;
-break;
-case 3:
-red=p;
-_519=q;
-blue=_517;
-break;
-case 4:
-red=t;
-_519=p;
-blue=_517;
-break;
-case 5:
-red=_517;
-_519=p;
-blue=q;
-break;
-case 6:
-case 0:
-red=_517;
-_519=t;
-blue=p;
-break;
-}
-}
-return {r:red,g:_519,b:blue,a:_518};
-},hslToRGB:function(hue,_521,_522,_523){
-if(arguments.length==1){
-var hsl=hue;
-hue=hsl.h;
-_521=hsl.s;
-_522=hsl.l;
-_523=hsl.a;
-}
-var red;
-var _524;
-var blue;
-if(_521===0){
-red=_522;
-_524=_522;
-blue=_522;
-}else{
-var m2;
-if(_522<=0.5){
-m2=_522*(1+_521);
-}else{
-m2=_522+_521-(_522*_521);
-}
-var m1=(2*_522)-m2;
-var f=MochiKit.Color._hslValue;
-var h6=hue*6;
-red=f(m1,m2,h6+2);
-_524=f(m1,m2,h6);
-blue=f(m1,m2,h6-2);
-}
-return {r:red,g:_524,b:blue,a:_523};
-},rgbToHSV:function(red,_528,blue,_529){
-if(arguments.length==1){
-var rgb=red;
-red=rgb.r;
-_528=rgb.g;
-blue=rgb.b;
-_529=rgb.a;
-}
-var max=Math.max(Math.max(red,_528),blue);
-var min=Math.min(Math.min(red,_528),blue);
-var hue;
-var _532;
-var _533=max;
-if(min==max){
-hue=0;
-_532=0;
-}else{
-var _534=(max-min);
-_532=_534/max;
-if(red==max){
-hue=(_528-blue)/_534;
-}else{
-if(_528==max){
-hue=2+((blue-red)/_534);
-}else{
-hue=4+((red-_528)/_534);
-}
-}
-hue/=6;
-if(hue<0){
-hue+=1;
-}
-if(hue>1){
-hue-=1;
-}
-}
-return {h:hue,s:_532,v:_533,a:_529};
-},rgbToHSL:function(red,_535,blue,_536){
-if(arguments.length==1){
-var rgb=red;
-red=rgb.r;
-_535=rgb.g;
-blue=rgb.b;
-_536=rgb.a;
-}
-var max=Math.max(red,Math.max(_535,blue));
-var min=Math.min(red,Math.min(_535,blue));
-var hue;
-var _537;
-var _538=(max+min)/2;
-var _539=max-min;
-if(_539===0){
-hue=0;
-_537=0;
-}else{
-if(_538<=0.5){
-_537=_539/(max+min);
-}else{
-_537=_539/(2-max-min);
-}
-if(red==max){
-hue=(_535-blue)/_539;
-}else{
-if(_535==max){
-hue=2+((blue-red)/_539);
-}else{
-hue=4+((red-_535)/_539);
-}
-}
-hue/=6;
-if(hue<0){
-hue+=1;
-}
-if(hue>1){
-hue-=1;
-}
-}
-return {h:hue,s:_537,l:_538,a:_536};
-},toColorPart:function(num){
-num=Math.round(num);
-var _540=num.toString(16);
-if(num<16){
-return "0"+_540;
-}
-return _540;
-},__new__:function(){
-var m=MochiKit.Base;
-this.Color.fromRGBString=m.bind(this.Color._fromColorString,this.Color,"rgb","fromRGB",[1/255,1/255,1/255,1]);
-this.Color.fromHSLString=m.bind(this.Color._fromColorString,this.Color,"hsl","fromHSL",[1/360,0.01,0.01,1]);
-var _541=1/3;
-var _542={black:[0,0,0],blue:[0,0,1],brown:[0.6,0.4,0.2],cyan:[0,1,1],darkGray:[_541,_541,_541],gray:[0.5,0.5,0.5],green:[0,1,0],lightGray:[2*_541,2*_541,2*_541],magenta:[1,0,1],orange:[1,0.5,0],purple:[0.5,0,0.5],red:[1,0,0],transparent:[0,0,0,0],white:[1,1,1],yellow:[1,1,0]};
-var _543=function(name,r,g,b,a){
-var rval=this.fromRGB(r,g,b,a);
-this[name]=function(){
-return rval;
-};
-return rval;
-};
-for(var k in _542){
-var name=k+"Color";
-var _545=m.concat([_543,this.Color,name],_542[k]);
-this.Color[name]=m.bind.apply(null,_545);
-}
-var _546=function(){
-for(var i=0;i<arguments.length;i++){
-if(!(arguments[i] instanceof Color)){
-return false;
-}
-}
-return true;
-};
-var _547=function(a,b){
-return a.compareRGB(b);
-};
-m.nameFunctions(this);
-m.registerComparator(this.Color.NAME,_546,_547);
-this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
-}});
-MochiKit.Color.EXPORT=["Color"];
-MochiKit.Color.EXPORT_OK=["clampColorComponent","rgbToHSL","hslToRGB","rgbToHSV","hsvToRGB","toColorPart"];
-MochiKit.Color.__new__();
-MochiKit.Base._exportSymbols(this,MochiKit.Color);
-MochiKit.Color.Color._namedColors={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"};
-if(typeof (dojo)!="undefined"){
-dojo.provide("MochiKit.Signal");
-dojo.require("MochiKit.Base");
-dojo.require("MochiKit.DOM");
-}
-if(typeof (JSAN)!="undefined"){
-JSAN.use("MochiKit.Base",[]);
-JSAN.use("MochiKit.DOM",[]);
-}
-try{
-if(typeof (MochiKit.Base)=="undefined"){
-throw "";
-}
-}
-catch(e){
-throw "MochiKit.Signal depends on MochiKit.Base!";
-}
-try{
-if(typeof (MochiKit.DOM)=="undefined"){
-throw "";
-}
-}
-catch(e){
-throw "MochiKit.Signal depends on MochiKit.DOM!";
-}
-if(typeof (MochiKit.Signal)=="undefined"){
-MochiKit.Signal={};
-}
-MochiKit.Signal.NAME="MochiKit.Signal";
-MochiKit.Signal.VERSION="1.3.1";
-MochiKit.Signal._observers=[];
-MochiKit.Signal.Event=function(src,e){
-this._event=e||window.event;
-this._src=src;
-};
-MochiKit.Base.update(MochiKit.Signal.Event.prototype,{__repr__:function(){
-var repr=MochiKit.Base.repr;
-var str="{event(): "+repr(this.event())+", src(): "+repr(this.src())+", type(): "+repr(this.type())+", target(): "+repr(this.target())+", modifier(): "+"{alt: "+repr(this.modifier().alt)+", ctrl: "+repr(this.modifier().ctrl)+", meta: "+repr(this.modifier().meta)+", shift: "+repr(this.modifier().shift)+", any: "+repr(this.modifier().any)+"}";
-if(this.type()&&this.type().indexOf("key")===0){
-str+=", key(): {code: "+repr(this.key().code)+", string: "+repr(this.key().string)+"}";
-}
-if(this.type()&&(this.type().indexOf("mouse")===0||this.type().indexOf("click")!=-1||this.type()=="contextmenu")){
-str+=", mouse(): {page: "+repr(this.mouse().page)+", client: "+repr(this.mouse().client);
-if(this.type()!="mousemove"){
-str+=", button: {left: "+repr(this.mouse().button.left)+", middle: "+repr(this.mouse().button.middle)+", right: "+repr(this.mouse().button.right)+"}}";
-}else{
-str+="}";
-}
-}
-if(this.type()=="mouseover"||this.type()=="mouseout"){
-str+=", relatedTarget(): "+repr(this.relatedTarget());
-}
-str+="}";
-return str;
-},toString:function(){
-return this.__repr__();
-},src:function(){
-return this._src;
-},event:function(){
-return this._event;
-},type:function(){
-return this._event.type||undefined;
-},target:function(){
-return this._event.target||this._event.srcElement;
-},relatedTarget:function(){
-if(this.type()=="mouseover"){
-return (this._event.relatedTarget||this._event.fromElement);
-}else{
-if(this.type()=="mouseout"){
-return (this._event.relatedTarget||this._event.toElement);
-}
-}
-return undefined;
-},modifier:function(){
-var m={};
-m.alt=this._event.altKey;
-m.ctrl=this._event.ctrlKey;
-m.meta=this._event.metaKey||false;
-m.shift=this._event.shiftKey;
-m.any=m.alt||m.ctrl||m.shift||m.meta;
-return m;
-},key:function(){
-var k={};
-if(this.type()&&this.type().indexOf("key")===0){
-if(this.type()=="keydown"||this.type()=="keyup"){
-k.code=this._event.keyCode;
-k.string=(MochiKit.Signal._specialKeys[k.code]||"KEY_UNKNOWN");
-return k;
-}else{
-if(this.type()=="keypress"){
-k.code=0;
-k.string="";
-if(typeof (this._event.charCode)!="undefined"&&this._event.charCode!==0&&!MochiKit.Signal._specialMacKeys[this._event.charCode]){
-k.code=this._event.charCode;
-k.string=String.fromCharCode(k.code);
-}else{
-if(this._event.keyCode&&typeof (this._event.charCode)=="undefined"){
-k.code=this._event.keyCode;
-k.string=String.fromCharCode(k.code);
-}
-}
-return k;
-}
-}
-}
-return undefined;
-},mouse:function(){
-var m={};
-var e=this._event;
-if(this.type()&&(this.type().indexOf("mouse")===0||this.type().indexOf("click")!=-1||this.type()=="contextmenu")){
-m.client=new MochiKit.DOM.Coordinates(0,0);
-if(e.clientX||e.clientY){
-m.client.x=(!e.clientX||e.clientX<0)?0:e.clientX;
-m.client.y=(!e.clientY||e.clientY<0)?0:e.clientY;
-}
-m.page=new MochiKit.DOM.Coordinates(0,0);
-if(e.pageX||e.pageY){
-m.page.x=(!e.pageX||e.pageX<0)?0:e.pageX;
-m.page.y=(!e.pageY||e.pageY<0)?0:e.pageY;
-}else{
-var de=MochiKit.DOM._document.documentElement;
-var b=MochiKit.DOM._document.body;
-m.page.x=e.clientX+(de.scrollLeft||b.scrollLeft)-(de.clientLeft||b.clientLeft);
-m.page.y=e.clientY+(de.scrollTop||b.scrollTop)-(de.clientTop||b.clientTop);
-}
-if(this.type()!="mousemove"){
-m.button={};
-m.button.left=false;
-m.button.right=false;
-m.button.middle=false;
-if(e.which){
-m.button.left=(e.which==1);
-m.button.middle=(e.which==2);
-m.button.right=(e.which==3);
-}else{
-m.button.left=!!(e.button&1);
-m.button.right=!!(e.button&2);
-m.button.middle=!!(e.button&4);
-}
-}
-return m;
-}
-return undefined;
-},stop:function(){
-this.stopPropagation();
-this.preventDefault();
-},stopPropagation:function(){
-if(this._event.stopPropagation){
-this._event.stopPropagation();
-}else{
-this._event.cancelBubble=true;
-}
-},preventDefault:function(){
-if(this._event.preventDefault){
-this._event.preventDefault();
-}else{
-this._event.returnValue=false;
-}
-}});
-MochiKit.Signal._specialMacKeys={3:"KEY_ENTER",63289:"KEY_NUM_PAD_CLEAR",63276:"KEY_PAGE_UP",63277:"KEY_PAGE_DOWN",63275:"KEY_END",63273:"KEY_HOME",63234:"KEY_ARROW_LEFT",63232:"KEY_ARROW_UP",63235:"KEY_ARROW_RIGHT",63233:"KEY_ARROW_DOWN",63302:"KEY_INSERT",63272:"KEY_DELETE"};
-for(i=63236;i<=63242;i++){
-MochiKit.Signal._specialMacKeys[i]="KEY_F"+(i-63236+1);
-}
-MochiKit.Signal._specialKeys={8:"KEY_BACKSPACE",9:"KEY_TAB",12:"KEY_NUM_PAD_CLEAR",13:"KEY_ENTER",16:"KEY_SHIFT",17:"KEY_CTRL",18:"KEY_ALT",19:"KEY_PAUSE",20:"KEY_CAPS_LOCK",27:"KEY_ESCAPE",32:"KEY_SPACEBAR",33:"KEY_PAGE_UP",34:"KEY_PAGE_DOWN",35:"KEY_END",36:"KEY_HOME",37:"KEY_ARROW_LEFT",38:"KEY_ARROW_UP",39:"KEY_ARROW_RIGHT",40:"KEY_ARROW_DOWN",44:"KEY_PRINT_SCREEN",45:"KEY_INSERT",46:"KEY_DELETE",59:"KEY_SEMICOLON",91:"KEY_WINDOWS_LEFT",92:"KEY_WINDOWS_RIGHT",93:"KEY_SELECT",106:"KEY_NUM_PAD_ASTERISK",107:"KEY_NUM_PAD_PLUS_SIGN",109:"KEY_NUM_PAD_HYPHEN-MINUS",110:"KEY_NUM_PAD_FULL_STOP",111:"KEY_NUM_PAD_SOLIDUS",144:"KEY_NUM_LOCK",145:"KEY_SCROLL_LOCK",186:"KEY_SEMICOLON",187:"KEY_EQUALS_SIGN",188:"KEY_COMMA",189:"KEY_HYPHEN-MINUS",190:"KEY_FULL_STOP",191:"KEY_SOLIDUS",192:"KEY_GRAVE_ACCENT",219:"KEY_LEFT_SQUARE_BRACKET",220:"KEY_REVERSE_SOLIDUS",221:"KEY_RIGHT_SQUARE_BRACKET",222:"KEY_APOSTROPHE"};
-for(var i=48;i<=57;i++){
-MochiKit.Signal._specialKeys[i]="KEY_"+(i-48);
-}
-for(i=65;i<=90;i++){
-MochiKit.Signal._specialKeys[i]="KEY_"+String.fromCharCode(i);
-}
-for(i=96;i<=105;i++){
-MochiKit.Signal._specialKeys[i]="KEY_NUM_PAD_"+(i-96);
-}
-for(i=112;i<=123;i++){
-MochiKit.Signal._specialKeys[i]="KEY_F"+(i-112+1);
-}
-MochiKit.Base.update(MochiKit.Signal,{__repr__:function(){
-return "["+this.NAME+" "+this.VERSION+"]";
-},toString:function(){
-return this.__repr__();
-},_unloadCache:function(){
-var self=MochiKit.Signal;
-var _548=self._observers;
-for(var i=0;i<_548.length;i++){
-self._disconnect(_548[i]);
-}
-delete self._observers;
-try{
-window.onload=undefined;
-}
-catch(e){
-}
-try{
-window.onunload=undefined;
-}
-catch(e){
-}
-},_listener:function(src,func,obj,_549){
-var E=MochiKit.Signal.Event;
-if(!_549){
-return MochiKit.Base.bind(func,obj);
-}
-obj=obj||src;
-if(typeof (func)=="string"){
-return function(_551){
-obj[func].apply(obj,[new E(src,_551)]);
-};
-}else{
-return function(_552){
-func.apply(obj,[new E(src,_552)]);
-};
-}
-},connect:function(src,sig,_554,_555){
-src=MochiKit.DOM.getElement(src);
-var self=MochiKit.Signal;
-if(typeof (sig)!="string"){
-throw new Error("'sig' must be a string");
-}
-var obj=null;
-var func=null;
-if(typeof (_555)!="undefined"){
-obj=_554;
-func=_555;
-if(typeof (_555)=="string"){
-if(typeof (_554[_555])!="function"){
-throw new Error("'funcOrStr' must be a function on 'objOrFunc'");
-}
-}else{
-if(typeof (_555)!="function"){
-throw new Error("'funcOrStr' must be a function or string");
-}
-}
-}else{
-if(typeof (_554)!="function"){
-throw new Error("'objOrFunc' must be a function if 'funcOrStr' is not given");
-}else{
-func=_554;
-}
-}
-if(typeof (obj)=="undefined"||obj===null){
-obj=src;
-}
-var _556=!!(src.addEventListener||src.attachEvent);
-var _557=self._listener(src,func,obj,_556);
-if(src.addEventListener){
-src.addEventListener(sig.substr(2),_557,false);
-}else{
-if(src.attachEvent){
-src.attachEvent(sig,_557);
-}
-}
-var _558=[src,sig,_557,_556,_554,_555];
-self._observers.push(_558);
-return _558;
-},_disconnect:function(_559){
-if(!_559[3]){
-return;
-}
-var src=_559[0];
-var sig=_559[1];
-var _560=_559[2];
-if(src.removeEventListener){
-src.removeEventListener(sig.substr(2),_560,false);
-}else{
-if(src.detachEvent){
-src.detachEvent(sig,_560);
-}else{
-throw new Error("'src' must be a DOM element");
-}
-}
-},disconnect:function(_561){
-var self=MochiKit.Signal;
-var _562=self._observers;
-var m=MochiKit.Base;
-if(arguments.length>1){
-var src=MochiKit.DOM.getElement(arguments[0]);
-var sig=arguments[1];
-var obj=arguments[2];
-var func=arguments[3];
-for(var i=_562.length-1;i>=0;i--){
-var o=_562[i];
-if(o[0]===src&&o[1]===sig&&o[4]===obj&&o[5]===func){
-self._disconnect(o);
-_562.splice(i,1);
-return true;
-}
-}
-}else{
-var idx=m.findIdentical(_562,_561);
-if(idx>=0){
-self._disconnect(_561);
-_562.splice(idx,1);
-return true;
-}
-}
-return false;
-},disconnectAll:function(src,sig){
-src=MochiKit.DOM.getElement(src);
-var m=MochiKit.Base;
-var _563=m.flattenArguments(m.extend(null,arguments,1));
-var self=MochiKit.Signal;
-var _564=self._disconnect;
-var _565=self._observers;
-if(_563.length===0){
-for(var i=_565.length-1;i>=0;i--){
-var _566=_565[i];
-if(_566[0]===src){
-_564(_566);
-_565.splice(i,1);
-}
-}
-}else{
-var sigs={};
-for(var i=0;i<_563.length;i++){
-sigs[_563[i]]=true;
-}
-for(var i=_565.length-1;i>=0;i--){
-var _566=_565[i];
-if(_566[0]===src&&_566[1] in sigs){
-_564(_566);
-_565.splice(i,1);
-}
-}
-}
-},signal:function(src,sig){
-var _568=MochiKit.Signal._observers;
-src=MochiKit.DOM.getElement(src);
-var args=MochiKit.Base.extend(null,arguments,2);
-var _569=[];
-for(var i=0;i<_568.length;i++){
-var _570=_568[i];
-if(_570[0]===src&&_570[1]===sig){
-try{
-_570[2].apply(src,args);
-}
-catch(e){
-_569.push(e);
-}
-}
-}
-if(_569.length==1){
-throw _569[0];
-}else{
-if(_569.length>1){
-var e=new Error("Multiple errors thrown in handling 'sig', see errors property");
-e.errors=_569;
-throw e;
-}
-}
-}});
-MochiKit.Signal.EXPORT_OK=[];
-MochiKit.Signal.EXPORT=["connect","disconnect","signal","disconnectAll"];
-MochiKit.Signal.__new__=function(win){
-var m=MochiKit.Base;
-this._document=document;
-this._window=win;
-try{
-this.connect(window,"onunload",this._unloadCache);
-}
-catch(e){
-}
-this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
-m.nameFunctions(this);
-};
-MochiKit.Signal.__new__(this);
-if(!MochiKit.__compat__){
-connect=MochiKit.Signal.connect;
-disconnect=MochiKit.Signal.disconnect;
-disconnectAll=MochiKit.Signal.disconnectAll;
-signal=MochiKit.Signal.signal;
-}
-MochiKit.Base._exportSymbols(this,MochiKit.Signal);
-if(typeof (dojo)!="undefined"){
-dojo.provide("MochiKit.Visual");
-dojo.require("MochiKit.Base");
-dojo.require("MochiKit.DOM");
-dojo.require("MochiKit.Color");
-}
-if(typeof (JSAN)!="undefined"){
-JSAN.use("MochiKit.Base",[]);
-JSAN.use("MochiKit.DOM",[]);
-JSAN.use("MochiKit.Color",[]);
-}
-try{
-if(typeof (MochiKit.Base)=="undefined"||typeof (MochiKit.DOM)=="undefined"||typeof (MochiKit.Color)=="undefined"){
-throw "";
-}
-}
-catch(e){
-throw "MochiKit.Visual depends on MochiKit.Base, MochiKit.DOM and MochiKit.Color!";
-}
-if(typeof (MochiKit.Visual)=="undefined"){
-MochiKit.Visual={};
-}
-MochiKit.Visual.NAME="MochiKit.Visual";
-MochiKit.Visual.VERSION="1.3.1";
-MochiKit.Visual.__repr__=function(){
-return "["+this.NAME+" "+this.VERSION+"]";
-};
-MochiKit.Visual.toString=function(){
-return this.__repr__();
-};
-MochiKit.Visual._RoundCorners=function(e,_571){
-e=MochiKit.DOM.getElement(e);
-this._setOptions(_571);
-if(this.options.__unstable__wrapElement){
-e=this._doWrap(e);
-}
-var _572=this.options.color;
-var C=MochiKit.Color.Color;
-if(this.options.color=="fromElement"){
-_572=C.fromBackground(e);
-}else{
-if(!(_572 instanceof C)){
-_572=C.fromString(_572);
-}
-}
-this.isTransparent=(_572.asRGB().a<=0);
-var _574=this.options.bgColor;
-if(this.options.bgColor=="fromParent"){
-_574=C.fromBackground(e.offsetParent);
-}else{
-if(!(_574 instanceof C)){
-_574=C.fromString(_574);
-}
-}
-this._roundCornersImpl(e,_572,_574);
-};
-MochiKit.Visual._RoundCorners.prototype={_doWrap:function(e){
-var _575=e.parentNode;
-var doc=MochiKit.DOM.currentDocument();
-if(typeof (doc.defaultView)=="undefined"||doc.defaultView===null){
-return e;
-}
-var _576=doc.defaultView.getComputedStyle(e,null);
-if(typeof (_576)=="undefined"||_576===null){
-return e;
-}
-var _577=MochiKit.DOM.DIV({"style":{display:"block",marginTop:_576.getPropertyValue("padding-top"),marginRight:_576.getPropertyValue("padding-right"),marginBottom:_576.getPropertyValue("padding-bottom"),marginLeft:_576.getPropertyValue("padding-left"),padding:"0px"}});
-_577.innerHTML=e.innerHTML;
-e.innerHTML="";
-e.appendChild(_577);
-return e;
-},_roundCornersImpl:function(e,_578,_579){
-if(this.options.border){
-this._renderBorder(e,_579);
-}
-if(this._isTopRounded()){
-this._roundTopCorners(e,_578,_579);
-}
-if(this._isBottomRounded()){
-this._roundBottomCorners(e,_578,_579);
-}
-},_renderBorder:function(el,_580){
-var _581="1px solid "+this._borderColor(_580);
-var _582="border-left: "+_581;
-var _583="border-right: "+_581;
-var _584="style='"+_582+";"+_583+"'";
-el.innerHTML="<div "+_584+">"+el.innerHTML+"</div>";
-},_roundTopCorners:function(el,_585,_586){
-var _587=this._createCorner(_586);
-for(var i=0;i<this.options.numSlices;i++){
-_587.appendChild(this._createCornerSlice(_585,_586,i,"top"));
-}
-el.style.paddingTop=0;
-el.insertBefore(_587,el.firstChild);
-},_roundBottomCorners:function(el,_588,_589){
-var _590=this._createCorner(_589);
-for(var i=(this.options.numSlices-1);i>=0;i--){
-_590.appendChild(this._createCornerSlice(_588,_589,i,"bottom"));
-}
-el.style.paddingBottom=0;
-el.appendChild(_590);
-},_createCorner:function(_591){
-var dom=MochiKit.DOM;
-return dom.DIV({style:{backgroundColor:_591.toString()}});
-},_createCornerSlice:function(_592,_593,n,_594){
-var _595=MochiKit.DOM.SPAN();
-var _596=_595.style;
-_596.backgroundColor=_592.toString();
-_596.display="block";
-_596.height="1px";
-_596.overflow="hidden";
-_596.fontSize="1px";
-var _597=this._borderColor(_592,_593);
-if(this.options.border&&n===0){
-_596.borderTopStyle="solid";
-_596.borderTopWidth="1px";
-_596.borderLeftWidth="0px";
-_596.borderRightWidth="0px";
-_596.borderBottomWidth="0px";
-_596.height="0px";
-_596.borderColor=_597.toString();
-}else{
-if(_597){
-_596.borderColor=_597.toString();
-_596.borderStyle="solid";
-_596.borderWidth="0px 1px";
-}
-}
-if(!this.options.compact&&(n==(this.options.numSlices-1))){
-_596.height="2px";
-}
-this._setMargin(_595,n,_594);
-this._setBorder(_595,n,_594);
-return _595;
-},_setOptions:function(_598){
-this.options={corners:"all",color:"fromElement",bgColor:"fromParent",blend:true,border:false,compact:false,__unstable__wrapElement:false};
-MochiKit.Base.update(this.options,_598);
-this.options.numSlices=(this.options.compact?2:4);
-},_whichSideTop:function(){
-var _599=this.options.corners;
-if(this._hasString(_599,"all","top")){
-return "";
-}
-var _600=(_599.indexOf("tl")!=-1);
-var _601=(_599.indexOf("tr")!=-1);
-if(_600&&_601){
-return "";
-}
-if(_600){
-return "left";
-}
-if(_601){
-return "right";
-}
-return "";
-},_whichSideBottom:function(){
-var _602=this.options.corners;
-if(this._hasString(_602,"all","bottom")){
-return "";
-}
-var _603=(_602.indexOf("bl")!=-1);
-var _604=(_602.indexOf("br")!=-1);
-if(_603&&_604){
-return "";
-}
-if(_603){
-return "left";
-}
-if(_604){
-return "right";
-}
-return "";
-},_borderColor:function(_605,_606){
-if(_605=="transparent"){
-return _606;
-}else{
-if(this.options.border){
-return this.options.border;
-}else{
-if(this.options.blend){
-return _606.blendedColor(_605);
-}
-}
-}
-return "";
-},_setMargin:function(el,n,_607){
-var _608=this._marginSize(n)+"px";
-var _609=(_607=="top"?this._whichSideTop():this._whichSideBottom());
-var _610=el.style;
-if(_609=="left"){
-_610.marginLeft=_608;
-_610.marginRight="0px";
-}else{
-if(_609=="right"){
-_610.marginRight=_608;
-_610.marginLeft="0px";
-}else{
-_610.marginLeft=_608;
-_610.marginRight=_608;
-}
-}
-},_setBorder:function(el,n,_611){
-var _612=this._borderSize(n)+"px";
-var _613=(_611=="top"?this._whichSideTop():this._whichSideBottom());
-var _614=el.style;
-if(_613=="left"){
-_614.borderLeftWidth=_612;
-_614.borderRightWidth="0px";
-}else{
-if(_613=="right"){
-_614.borderRightWidth=_612;
-_614.borderLeftWidth="0px";
-}else{
-_614.borderLeftWidth=_612;
-_614.borderRightWidth=_612;
-}
-}
-},_marginSize:function(n){
-if(this.isTransparent){
-return 0;
-}
-var o=this.options;
-if(o.compact&&o.blend){
-var _615=[1,0];
-return _615[n];
-}else{
-if(o.compact){
-var _616=[2,1];
-return _616[n];
-}else{
-if(o.blend){
-var _617=[3,2,1,0];
-return _617[n];
-}else{
-var _618=[5,3,2,1];
-return _618[n];
-}
-}
-}
-},_borderSize:function(n){
-var o=this.options;
-var _619;
-if(o.compact&&(o.blend||this.isTransparent)){
-return 1;
-}else{
-if(o.compact){
-_619=[1,0];
-}else{
-if(o.blend){
-_619=[2,1,1,1];
-}else{
-if(o.border){
-_619=[0,2,0,0];
-}else{
-if(this.isTransparent){
-_619=[5,3,2,1];
-}else{
-return 0;
-}
-}
-}
-}
-}
-return _619[n];
-},_hasString:function(str){
-for(var i=1;i<arguments.length;i++){
-if(str.indexOf(arguments[i])!=-1){
-return true;
-}
-}
-return false;
-},_isTopRounded:function(){
-return this._hasString(this.options.corners,"all","top","tl","tr");
-},_isBottomRounded:function(){
-return this._hasString(this.options.corners,"all","bottom","bl","br");
-},_hasSingleTextChild:function(el){
-return (el.childNodes.length==1&&el.childNodes[0].nodeType==3);
-}};
-MochiKit.Visual.roundElement=function(e,_620){
-new MochiKit.Visual._RoundCorners(e,_620);
-};
-MochiKit.Visual.roundClass=function(_621,_622,_623){
-var _624=MochiKit.DOM.getElementsByTagAndClassName(_621,_622);
-for(var i=0;i<_624.length;i++){
-MochiKit.Visual.roundElement(_624[i],_623);
-}
-};
-MochiKit.Visual.Color=MochiKit.Color.Color;
-MochiKit.Visual.getElementsComputedStyle=MochiKit.DOM.computedStyle;
-MochiKit.Visual.__new__=function(){
-var m=MochiKit.Base;
-m.nameFunctions(this);
-this.EXPORT_TAGS={":common":this.EXPORT,":all":m.concat(this.EXPORT,this.EXPORT_OK)};
-};
-MochiKit.Visual.EXPORT=["roundElement","roundClass"];
-MochiKit.Visual.EXPORT_OK=[];
-MochiKit.Visual.__new__();
-MochiKit.Base._exportSymbols(this,MochiKit.Visual);
-if(typeof (MochiKit)=="undefined"){
-MochiKit={};
-}
-if(typeof (MochiKit.MochiKit)=="undefined"){
-MochiKit.MochiKit={};
-}
-MochiKit.MochiKit.NAME="MochiKit.MochiKit";
-MochiKit.MochiKit.VERSION="1.3.1";
-MochiKit.MochiKit.__repr__=function(){
-return "["+this.NAME+" "+this.VERSION+"]";
-};
-MochiKit.MochiKit.toString=function(){
-return this.__repr__();
-};
-MochiKit.MochiKit.SUBMODULES=["Base","Iter","Logging","DateTime","Format","Async","DOM","LoggingPane","Color","Signal","Visual"];
-if(typeof (JSAN)!="undefined"||typeof (dojo)!="undefined"){
-if(typeof (dojo)!="undefined"){
-dojo.provide("MochiKit.MochiKit");
-dojo.require("MochiKit.*");
-}
-if(typeof (JSAN)!="undefined"){
-JSAN.use("MochiKit.Base",[]);
-JSAN.use("MochiKit.Iter",[]);
-JSAN.use("MochiKit.Logging",[]);
-JSAN.use("MochiKit.DateTime",[]);
-JSAN.use("MochiKit.Format",[]);
-JSAN.use("MochiKit.Async",[]);
-JSAN.use("MochiKit.DOM",[]);
-JSAN.use("MochiKit.LoggingPane",[]);
-JSAN.use("MochiKit.Color",[]);
-JSAN.use("MochiKit.Signal",[]);
-JSAN.use("MochiKit.Visual",[]);
-}
-(function(){
-var _625=MochiKit.Base.extend;
-var self=MochiKit.MochiKit;
-var _626=self.SUBMODULES;
-var _627=[];
-var _628=[];
-var _629={};
-var i,k,m,all;
-for(i=0;i<_626.length;i++){
-m=MochiKit[_626[i]];
-_625(_627,m.EXPORT);
-_625(_628,m.EXPORT_OK);
-for(k in m.EXPORT_TAGS){
-_629[k]=_625(_629[k],m.EXPORT_TAGS[k]);
-}
-all=m.EXPORT_TAGS[":all"];
-if(!all){
-all=_625(null,m.EXPORT,m.EXPORT_OK);
-}
-var j;
-for(j=0;j<all.length;j++){
-k=all[j];
-self[k]=m[k];
-}
-}
-self.EXPORT=_627;
-self.EXPORT_OK=_628;
-self.EXPORT_TAGS=_629;
-}());
-}else{
-if(typeof (MochiKit.__compat__)=="undefined"){
-MochiKit.__compat__=true;
-}
-(function(){
-var _630=document.getElementsByTagName("script");
-var _631="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
-var base=null;
-var _632=null;
-var _633={};
-var i;
-for(i=0;i<_630.length;i++){
-var src=_630[i].getAttribute("src");
-if(!src){
-continue;
-}
-_633[src]=true;
-if(src.match(/MochiKit.js$/)){
-base=src.substring(0,src.lastIndexOf("MochiKit.js"));
-_632=_630[i];
-}
-}
-if(base===null){
-return;
-}
-var _634=MochiKit.MochiKit.SUBMODULES;
-for(var i=0;i<_634.length;i++){
-if(MochiKit[_634[i]]){
-continue;
-}
-var uri=base+_634[i]+".js";
-if(uri in _633){
-continue;
-}
-if(document.documentElement&&document.documentElement.namespaceURI==_631){
-var s=document.createElementNS(_631,"script");
-s.setAttribute("id","MochiKit_"+base+_634[i]);
-s.setAttribute("src",uri);
-s.setAttribute("type","application/x-javascript");
-_632.parentNode.appendChild(s);
-}else{
-document.write("<script src=\""+uri+"\" type=\"text/javascript\"></script>");
-}
-}
-})();
-}
-
-
diff --git a/lib/paste/evalexception/mochikit/__package__.js b/lib/paste/evalexception/mochikit/__package__.js
@@ -1,2 +0,0 @@
-dojo.hostenv.conditionalLoadModule({"common": ["MochiKit.MochiKit"]});
-dojo.hostenv.moduleLoaded("MochiKit.*");
diff --git a/lib/paste/exceptions/__init__.py b/lib/paste/exceptions/__init__.py
@@ -1,6 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-Package for catching exceptions and displaying annotated exception
-reports
-"""
diff --git a/lib/paste/exceptions/collector.py b/lib/paste/exceptions/collector.py
@@ -1,526 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-##############################################################################
-#
-# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
-# All Rights Reserved.
-#
-# This software is subject to the provisions of the Zope Public License,
-# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
-# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
-# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-##############################################################################
-## Originally zExceptions.ExceptionFormatter from Zope;
-## Modified by Ian Bicking, Imaginary Landscape, 2005
-"""
-An exception collector that finds traceback information plus
-supplements
-"""
-
-import sys
-import traceback
-import time
-try:
-    from cStringIO import StringIO
-except ImportError:
-    from StringIO import StringIO
-import linecache
-from paste.exceptions import serial_number_generator
-import warnings
-
-DEBUG_EXCEPTION_FORMATTER = True
-DEBUG_IDENT_PREFIX = 'E-'
-FALLBACK_ENCODING = 'UTF-8'
-
-__all__ = ['collect_exception', 'ExceptionCollector']
-
-class ExceptionCollector(object):
-
-    """
-    Produces a data structure that can be used by formatters to
-    display exception reports.
-
-    Magic variables:
-
-    If you define one of these variables in your local scope, you can
-    add information to tracebacks that happen in that context.  This
-    allows applications to add all sorts of extra information about
-    the context of the error, including URLs, environmental variables,
-    users, hostnames, etc.  These are the variables we look for:
-
-    ``__traceback_supplement__``:
-        You can define this locally or globally (unlike all the other
-        variables, which must be defined locally).
-
-        ``__traceback_supplement__`` is a tuple of ``(factory, arg1,
-        arg2...)``.  When there is an exception, ``factory(arg1, arg2,
-        ...)`` is called, and the resulting object is inspected for
-        supplemental information.
-
-    ``__traceback_info__``:
-        This information is added to the traceback, usually fairly
-        literally.
-
-    ``__traceback_hide__``:
-        If set and true, this indicates that the frame should be
-        hidden from abbreviated tracebacks.  This way you can hide
-        some of the complexity of the larger framework and let the
-        user focus on their own errors.
-
-        By setting it to ``'before'``, all frames before this one will
-        be thrown away.  By setting it to ``'after'`` then all frames
-        after this will be thrown away until ``'reset'`` is found.  In
-        each case the frame where it is set is included, unless you
-        append ``'_and_this'`` to the value (e.g.,
-        ``'before_and_this'``).
-
-        Note that formatters will ignore this entirely if the frame
-        that contains the error wouldn't normally be shown according
-        to these rules.
-
-    ``__traceback_reporter__``:
-        This should be a reporter object (see the reporter module),
-        or a list/tuple of reporter objects.  All reporters found this
-        way will be given the exception, innermost first.
-
-    ``__traceback_decorator__``:
-        This object (defined in a local or global scope) will get the
-        result of this function (the CollectedException defined
-        below).  It may modify this object in place, or return an
-        entirely new object.  This gives the object the ability to
-        manipulate the traceback arbitrarily.
-
-    The actually interpretation of these values is largely up to the
-    reporters and formatters.
-    
-    ``collect_exception(*sys.exc_info())`` will return an object with
-    several attributes:
-
-    ``frames``:
-        A list of frames
-    ``exception_formatted``:
-        The formatted exception, generally a full traceback
-    ``exception_type``:
-        The type of the exception, like ``ValueError``
-    ``exception_value``:
-        The string value of the exception, like ``'x not in list'``
-    ``identification_code``:
-        A hash of the exception data meant to identify the general
-        exception, so that it shares this code with other exceptions
-        that derive from the same problem.  The code is a hash of
-        all the module names and function names in the traceback,
-        plus exception_type.  This should be shown to users so they
-        can refer to the exception later. (@@: should it include a
-        portion that allows identification of the specific instance
-        of the exception as well?)
-        
-    The list of frames goes innermost first.  Each frame has these
-    attributes; some values may be None if they could not be
-    determined.
-
-    ``modname``:
-        the name of the module
-    ``filename``:
-        the filename of the module
-    ``lineno``:
-        the line of the error
-    ``revision``:
-        the contents of __version__ or __revision__
-    ``name``:
-        the function name
-    ``supplement``:
-        an object created from ``__traceback_supplement__``
-    ``supplement_exception``:
-        a simple traceback of any exception ``__traceback_supplement__``
-        created
-    ``traceback_info``:
-        the str() of any ``__traceback_info__`` variable found in the local
-        scope (@@: should it str()-ify it or not?)
-    ``traceback_hide``:
-        the value of any ``__traceback_hide__`` variable
-    ``traceback_log``:
-        the value of any ``__traceback_log__`` variable
-    
-
-    ``__traceback_supplement__`` is thrown away, but a fixed
-    set of attributes are captured; each of these attributes is
-    optional.
-
-    ``object``:
-        the name of the object being visited
-    ``source_url``:
-        the original URL requested
-    ``line``:
-        the line of source being executed (for interpreters, like ZPT)
-    ``column``:
-        the column of source being executed
-    ``expression``:
-        the expression being evaluated (also for interpreters)
-    ``warnings``:
-        a list of (string) warnings to be displayed
-    ``getInfo``:
-        a function/method that takes no arguments, and returns a string
-        describing any extra information
-    ``extraData``:
-        a function/method that takes no arguments, and returns a
-        dictionary.  The contents of this dictionary will not be
-        displayed in the context of the traceback, but globally for
-        the exception.  Results will be grouped by the keys in the
-        dictionaries (which also serve as titles).  The keys can also
-        be tuples of (importance, title); in this case the importance
-        should be ``important`` (shows up at top), ``normal`` (shows
-        up somewhere; unspecified), ``supplemental`` (shows up at
-        bottom), or ``extra`` (shows up hidden or not at all).
-
-    These are used to create an object with attributes of the same
-    names (``getInfo`` becomes a string attribute, not a method).
-    ``__traceback_supplement__`` implementations should be careful to
-    produce values that are relatively static and unlikely to cause
-    further errors in the reporting system -- any complex
-    introspection should go in ``getInfo()`` and should ultimately
-    return a string.
-
-    Note that all attributes are optional, and under certain
-    circumstances may be None or may not exist at all -- the collector
-    can only do a best effort, but must avoid creating any exceptions
-    itself.
-
-    Formatters may want to use ``__traceback_hide__`` as a hint to
-    hide frames that are part of the 'framework' or underlying system.
-    There are a variety of rules about special values for this
-    variables that formatters should be aware of.
-    
-    TODO:
-
-    More attributes in __traceback_supplement__?  Maybe an attribute
-    that gives a list of local variables that should also be
-    collected?  Also, attributes that would be explicitly meant for
-    the entire request, not just a single frame.  Right now some of
-    the fixed set of attributes (e.g., source_url) are meant for this
-    use, but there's no explicit way for the supplement to indicate
-    new values, e.g., logged-in user, HTTP referrer, environment, etc.
-    Also, the attributes that do exist are Zope/Web oriented.
-
-    More information on frames?  cgitb, for instance, produces
-    extensive information on local variables.  There exists the
-    possibility that getting this information may cause side effects,
-    which can make debugging more difficult; but it also provides
-    fodder for post-mortem debugging.  However, the collector is not
-    meant to be configurable, but to capture everything it can and let
-    the formatters be configurable.  Maybe this would have to be a
-    configuration value, or maybe it could be indicated by another
-    magical variable (which would probably mean 'show all local
-    variables below this frame')
-    """
-
-    show_revisions = 0
-
-    def __init__(self, limit=None):
-        self.limit = limit
-
-    def getLimit(self):
-        limit = self.limit
-        if limit is None:
-            limit = getattr(sys, 'tracebacklimit', None)
-        return limit
-
-    def getRevision(self, globals):
-        if not self.show_revisions:
-            return None
-        revision = globals.get('__revision__', None)
-        if revision is None:
-            # Incorrect but commonly used spelling
-            revision = globals.get('__version__', None)
-
-        if revision is not None:
-            try:
-                revision = str(revision).strip()
-            except:
-                revision = '???'
-        return revision
-
-    def collectSupplement(self, supplement, tb):
-        result = {}
-
-        for name in ('object', 'source_url', 'line', 'column',
-                     'expression', 'warnings'):
-            result[name] = getattr(supplement, name, None)
-
-        func = getattr(supplement, 'getInfo', None)
-        if func:
-            result['info'] = func()
-        else:
-            result['info'] = None
-        func = getattr(supplement, 'extraData', None)
-        if func:
-            result['extra'] = func()
-        else:
-            result['extra'] = None
-        return SupplementaryData(**result)
-
-    def collectLine(self, tb, extra_data):
-        f = tb.tb_frame
-        lineno = tb.tb_lineno
-        co = f.f_code
-        filename = co.co_filename
-        name = co.co_name
-        globals = f.f_globals
-        locals = f.f_locals
-        if not hasattr(locals, 'has_key'):
-            # Something weird about this frame; it's not a real dict
-            warnings.warn(
-                "Frame %s has an invalid locals(): %r" % (
-                globals.get('__name__', 'unknown'), locals))
-            locals = {}
-        data = {}
-        data['modname'] = globals.get('__name__', None)
-        data['filename'] = filename
-        data['lineno'] = lineno
-        data['revision'] = self.getRevision(globals)
-        data['name'] = name
-        data['tbid'] = id(tb)
-
-        # Output a traceback supplement, if any.
-        if locals.has_key('__traceback_supplement__'):
-            # Use the supplement defined in the function.
-            tbs = locals['__traceback_supplement__']
-        elif globals.has_key('__traceback_supplement__'):
-            # Use the supplement defined in the module.
-            # This is used by Scripts (Python).
-            tbs = globals['__traceback_supplement__']
-        else:
-            tbs = None
-        if tbs is not None:
-            factory = tbs[0]
-            args = tbs[1:]
-            try:
-                supp = factory(*args)
-                data['supplement'] = self.collectSupplement(supp, tb)
-                if data['supplement'].extra:
-                    for key, value in data['supplement'].extra.items():
-                        extra_data.setdefault(key, []).append(value)
-            except:
-                if DEBUG_EXCEPTION_FORMATTER:
-                    out = StringIO()
-                    traceback.print_exc(file=out)
-                    text = out.getvalue()
-                    data['supplement_exception'] = text
-                # else just swallow the exception.
-
-        try:
-            tbi = locals.get('__traceback_info__', None)
-            if tbi is not None:
-                data['traceback_info'] = str(tbi)
-        except:
-            pass
-
-        marker = []
-        for name in ('__traceback_hide__', '__traceback_log__',
-                     '__traceback_decorator__'):
-            try:
-                tbh = locals.get(name, globals.get(name, marker))
-                if tbh is not marker:
-                    data[name[2:-2]] = tbh
-            except:
-                pass
-
-        return data
-
-    def collectExceptionOnly(self, etype, value):
-        return traceback.format_exception_only(etype, value)
-
-    def collectException(self, etype, value, tb, limit=None):
-        # The next line provides a way to detect recursion.
-        __exception_formatter__ = 1
-        frames = []
-        ident_data = []
-        traceback_decorators = []
-        if limit is None:
-            limit = self.getLimit()
-        n = 0
-        extra_data = {}
-        while tb is not None and (limit is None or n < limit):
-            if tb.tb_frame.f_locals.get('__exception_formatter__'):
-                # Stop recursion. @@: should make a fake ExceptionFrame
-                frames.append('(Recursive formatException() stopped)\n')
-                break
-            data = self.collectLine(tb, extra_data)
-            frame = ExceptionFrame(**data)
-            frames.append(frame)
-            if frame.traceback_decorator is not None:
-                traceback_decorators.append(frame.traceback_decorator)
-            ident_data.append(frame.modname or '?')
-            ident_data.append(frame.name or '?')
-            tb = tb.tb_next
-            n = n + 1
-        ident_data.append(str(etype))
-        ident = serial_number_generator.hash_identifier(
-            ' '.join(ident_data), length=5, upper=True,
-            prefix=DEBUG_IDENT_PREFIX)
-
-        result = CollectedException(
-            frames=frames,
-            exception_formatted=self.collectExceptionOnly(etype, value),
-            exception_type=etype,
-            exception_value=self.safeStr(value),
-            identification_code=ident,
-            date=time.localtime(),
-            extra_data=extra_data)
-        if etype is ImportError:
-            extra_data[('important', 'sys.path')] = [sys.path]
-        for decorator in traceback_decorators:
-            try:
-                new_result = decorator(result)
-                if new_result is not None:
-                    result = new_result
-            except:
-                pass
-        return result
-
-    def safeStr(self, obj):
-        try:
-            return str(obj)
-        except UnicodeEncodeError:
-            try:
-                return unicode(obj).encode(FALLBACK_ENCODING, 'replace')
-            except UnicodeEncodeError:
-                # This is when something is really messed up, but this can
-                # happen when the __str__ of an object has to handle unicode
-                return repr(obj)
-
-limit = 200
-
-class Bunch(object):
-
-    """
-    A generic container
-    """
-
-    def __init__(self, **attrs):
-        for name, value in attrs.items():
-            setattr(self, name, value)
-
-    def __repr__(self):
-        name = '<%s ' % self.__class__.__name__
-        name += ' '.join(['%s=%r' % (name, str(value)[:30])
-                          for name, value in self.__dict__.items()
-                          if not name.startswith('_')])
-        return name + '>'
-
-class CollectedException(Bunch):
-    """
-    This is the result of collection the exception; it contains copies
-    of data of interest.
-    """
-    # A list of frames (ExceptionFrame instances), innermost last:
-    frames = []
-    # The result of traceback.format_exception_only; this looks
-    # like a normal traceback you'd see in the interactive interpreter
-    exception_formatted = None
-    # The *string* representation of the type of the exception
-    # (@@: should we give the # actual class? -- we can't keep the
-    # actual exception around, but the class should be safe)
-    # Something like 'ValueError'
-    exception_type = None
-    # The string representation of the exception, from ``str(e)``.
-    exception_value = None
-    # An identifier which should more-or-less classify this particular
-    # exception, including where in the code it happened.
-    identification_code = None
-    # The date, as time.localtime() returns:
-    date = None
-    # A dictionary of supplemental data:
-    extra_data = {}
-
-class SupplementaryData(Bunch):
-    """
-    The result of __traceback_supplement__.  We don't keep the
-    supplement object around, for fear of GC problems and whatnot.
-    (@@: Maybe I'm being too superstitious about copying only specific
-    information over)
-    """
-
-    # These attributes are copied from the object, or left as None
-    # if the object doesn't have these attributes:
-    object = None
-    source_url = None
-    line = None
-    column = None
-    expression = None
-    warnings = None
-    # This is the *return value* of supplement.getInfo():
-    info = None
-
-class ExceptionFrame(Bunch):
-    """
-    This represents one frame of the exception.  Each frame is a
-    context in the call stack, typically represented by a line
-    number and module name in the traceback.
-    """
-
-    # The name of the module; can be None, especially when the code
-    # isn't associated with a module.
-    modname = None
-    # The filename (@@: when no filename, is it None or '?'?)
-    filename = None
-    # Line number
-    lineno = None
-    # The value of __revision__ or __version__ -- but only if
-    # show_revision = True (by defaut it is false).  (@@: Why not
-    # collect this?)
-    revision = None
-    # The name of the function with the error (@@: None or '?' when
-    # unknown?)
-    name = None
-    # A SupplementaryData object, if __traceback_supplement__ was found
-    # (and produced no errors)
-    supplement = None
-    # If accessing __traceback_supplement__ causes any error, the
-    # plain-text traceback is stored here
-    supplement_exception = None
-    # The str() of any __traceback_info__ value found
-    traceback_info = None
-    # The value of __traceback_hide__
-    traceback_hide = False
-    # The value of __traceback_decorator__
-    traceback_decorator = None
-    # The id() of the traceback scope, can be used to reference the
-    # scope for use elsewhere
-    tbid = None
-
-    def get_source_line(self, context=0):
-        """
-        Return the source of the current line of this frame.  You
-        probably want to .strip() it as well, as it is likely to have
-        leading whitespace.
-
-        If context is given, then that many lines on either side will
-        also be returned.  E.g., context=1 will give 3 lines.
-        """
-        if not self.filename or not self.lineno:
-            return None
-        lines = []
-        for lineno in range(self.lineno-context, self.lineno+context+1):
-            lines.append(linecache.getline(self.filename, lineno))
-        return ''.join(lines)
-        
-if hasattr(sys, 'tracebacklimit'):
-    limit = min(limit, sys.tracebacklimit)
-
-col = ExceptionCollector()
-
-def collect_exception(t, v, tb, limit=None):
-    """
-    Collection an exception from ``sys.exc_info()``.
-    
-    Use like::
-
-      try:
-          blah blah
-      except:
-          exc_data = collect_exception(*sys.exc_info())
-    """
-    return col.collectException(t, v, tb, limit=limit)
diff --git a/lib/paste/exceptions/errormiddleware.py b/lib/paste/exceptions/errormiddleware.py
@@ -1,460 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-"""
-Error handler middleware
-"""
-import sys
-import traceback
-import cgi
-try:
-    from cStringIO import StringIO
-except ImportError:
-    from StringIO import StringIO
-from paste.exceptions import formatter, collector, reporter
-from paste import wsgilib
-from paste import request
-
-__all__ = ['ErrorMiddleware', 'handle_exception']
-
-class _NoDefault(object):
-    def __repr__(self):
-        return '<NoDefault>'
-NoDefault = _NoDefault()
-
-class ErrorMiddleware(object):
-
-    """
-    Error handling middleware
-    
-    Usage::
-
-        error_caching_wsgi_app = ErrorMiddleware(wsgi_app)
-
-    Settings:
-
-      ``debug``:
-          If true, then tracebacks will be shown in the browser.
-
-      ``error_email``:
-          an email address (or list of addresses) to send exception 
-          reports to
-
-      ``error_log``:
-          a filename to append tracebacks to
-
-      ``show_exceptions_in_wsgi_errors``:
-          If true, then errors will be printed to ``wsgi.errors`` 
-          (frequently a server error log, or stderr).
-
-      ``from_address``, ``smtp_server``, ``error_subject_prefix``, ``smtp_username``, ``smtp_password``, ``smtp_use_tls``:
-          variables to control the emailed exception reports
-
-      ``error_message``:
-          When debug mode is off, the error message to show to users.
-
-      ``xmlhttp_key``:
-          When this key (default ``_``) is in the request GET variables
-          (not POST!), expect that this is an XMLHttpRequest, and the
-          response should be more minimal; it should not be a complete
-          HTML page.
-
-    Environment Configuration:
-    
-      ``paste.throw_errors``:
-          If this setting in the request environment is true, then this
-          middleware is disabled. This can be useful in a testing situation
-          where you don't want errors to be caught and transformed.
-
-      ``paste.expected_exceptions``:
-          When this middleware encounters an exception listed in this
-          environment variable and when the ``start_response`` has not 
-          yet occurred, the exception will be re-raised instead of being
-          caught.  This should generally be set by middleware that may 
-          (but probably shouldn't be) installed above this middleware, 
-          and wants to get certain exceptions.  Exceptions raised after
-          ``start_response`` have been called are always caught since
-          by definition they are no longer expected.
-
-    """
-
-    def __init__(self, application, global_conf=None,
-                 debug=NoDefault,
-                 error_email=None,
-                 error_log=None,
-                 show_exceptions_in_wsgi_errors=NoDefault,
-                 from_address=None,
-                 smtp_server=None,
-                 smtp_username=None,
-                 smtp_password=None,
-                 smtp_use_tls=False,
-                 error_subject_prefix=None,
-                 error_message=None,
-                 xmlhttp_key=None):
-        from paste.util import converters
-        self.application = application
-        # @@: global_conf should be handled elsewhere in a separate
-        # function for the entry point
-        if global_conf is None:
-            global_conf = {}
-        if debug is NoDefault:
-            debug = converters.asbool(global_conf.get('debug'))
-        if show_exceptions_in_wsgi_errors is NoDefault:
-            show_exceptions_in_wsgi_errors = converters.asbool(global_conf.get('show_exceptions_in_wsgi_errors'))
-        self.debug_mode = converters.asbool(debug)
-        if error_email is None:
-            error_email = (global_conf.get('error_email')
-                           or global_conf.get('admin_email')
-                           or global_conf.get('webmaster_email')
-                           or global_conf.get('sysadmin_email'))
-        self.error_email = converters.aslist(error_email)
-        self.error_log = error_log
-        self.show_exceptions_in_wsgi_errors = show_exceptions_in_wsgi_errors
-        if from_address is None:
-            from_address = global_conf.get('error_from_address', 'errors@localhost')
-        self.from_address = from_address
-        if smtp_server is None:
-            smtp_server = global_conf.get('smtp_server', 'localhost')
-        self.smtp_server = smtp_server
-        self.smtp_username = smtp_username or global_conf.get('smtp_username')
-        self.smtp_password = smtp_password or global_conf.get('smtp_password')
-        self.smtp_use_tls = smtp_use_tls or converters.asbool(global_conf.get('smtp_use_tls'))
-        self.error_subject_prefix = error_subject_prefix or ''
-        if error_message is None:
-            error_message = global_conf.get('error_message')
-        self.error_message = error_message
-        if xmlhttp_key is None:
-            xmlhttp_key = global_conf.get('xmlhttp_key', '_')
-        self.xmlhttp_key = xmlhttp_key
-            
-    def __call__(self, environ, start_response):
-        """
-        The WSGI application interface.
-        """
-        # We want to be careful about not sending headers twice,
-        # and the content type that the app has committed to (if there
-        # is an exception in the iterator body of the response)
-        if environ.get('paste.throw_errors'):
-            return self.application(environ, start_response)
-        environ['paste.throw_errors'] = True
-
-        try:
-            __traceback_supplement__ = Supplement, self, environ
-            sr_checker = ResponseStartChecker(start_response)
-            app_iter = self.application(environ, sr_checker)
-            return self.make_catching_iter(app_iter, environ, sr_checker)
-        except:
-            exc_info = sys.exc_info()
-            try:
-                for expect in environ.get('paste.expected_exceptions', []):
-                    if isinstance(exc_info[1], expect):
-                        raise
-                start_response('500 Internal Server Error',
-                               [('content-type', 'text/html')],
-                               exc_info)
-                # @@: it would be nice to deal with bad content types here
-                response = self.exception_handler(exc_info, environ)
-                return [response]
-            finally:
-                # clean up locals...
-                exc_info = None
-
-    def make_catching_iter(self, app_iter, environ, sr_checker):
-        if isinstance(app_iter, (list, tuple)):
-            # These don't raise
-            return app_iter
-        return CatchingIter(app_iter, environ, sr_checker, self)
-
-    def exception_handler(self, exc_info, environ):
-        simple_html_error = False
-        if self.xmlhttp_key:
-            get_vars = wsgilib.parse_querystring(environ)
-            if dict(get_vars).get(self.xmlhttp_key):
-                simple_html_error = True
-        return handle_exception(
-            exc_info, environ['wsgi.errors'],
-            html=True,
-            debug_mode=self.debug_mode,
-            error_email=self.error_email,
-            error_log=self.error_log,
-            show_exceptions_in_wsgi_errors=self.show_exceptions_in_wsgi_errors,
-            error_email_from=self.from_address,
-            smtp_server=self.smtp_server,
-            smtp_username=self.smtp_username,
-            smtp_password=self.smtp_password,
-            smtp_use_tls=self.smtp_use_tls,
-            error_subject_prefix=self.error_subject_prefix,
-            error_message=self.error_message,
-            simple_html_error=simple_html_error)
-
-class ResponseStartChecker(object):
-    def __init__(self, start_response):
-        self.start_response = start_response
-        self.response_started = False
-
-    def __call__(self, *args):
-        self.response_started = True
-        self.start_response(*args)
-
-class CatchingIter(object):
-
-    """
-    A wrapper around the application iterator that will catch
-    exceptions raised by the a generator, or by the close method, and
-    display or report as necessary.
-    """
-
-    def __init__(self, app_iter, environ, start_checker, error_middleware):
-        self.app_iterable = app_iter
-        self.app_iterator = iter(app_iter)
-        self.environ = environ
-        self.start_checker = start_checker
-        self.error_middleware = error_middleware
-        self.closed = False
-
-    def __iter__(self):
-        return self
-
-    def next(self):
-        __traceback_supplement__ = (
-            Supplement, self.error_middleware, self.environ)
-        if self.closed:
-            raise StopIteration
-        try:
-            return self.app_iterator.next()
-        except StopIteration:
-            self.closed = True
-            close_response = self._close()
-            if close_response is not None:
-                return close_response
-            else:
-                raise StopIteration
-        except:
-            self.closed = True
-            close_response = self._close()
-            exc_info = sys.exc_info()
-            response = self.error_middleware.exception_handler(
-                exc_info, self.environ)
-            if close_response is not None:
-                response += (
-                    '<hr noshade>Error in .close():<br>%s'
-                    % close_response)
-
-            if not self.start_checker.response_started:
-                self.start_checker('500 Internal Server Error',
-                               [('content-type', 'text/html')],
-                               exc_info)
-
-            return response
-
-    def close(self):
-        # This should at least print something to stderr if the
-        # close method fails at this point
-        if not self.closed:
-            self._close()
-
-    def _close(self):
-        """Close and return any error message"""
-        if not hasattr(self.app_iterable, 'close'):
-            return None
-        try:
-            self.app_iterable.close()
-            return None
-        except:
-            close_response = self.error_middleware.exception_handler(
-                sys.exc_info(), self.environ)
-            return close_response
-
-
-class Supplement(object):
-
-    """
-    This is a supplement used to display standard WSGI information in
-    the traceback.
-    """
-
-    def __init__(self, middleware, environ):
-        self.middleware = middleware
-        self.environ = environ
-        self.source_url = request.construct_url(environ)
-
-    def extraData(self):
-        data = {}
-        cgi_vars = data[('extra', 'CGI Variables')] = {}
-        wsgi_vars = data[('extra', 'WSGI Variables')] = {}
-        hide_vars = ['paste.config', 'wsgi.errors', 'wsgi.input',
-                     'wsgi.multithread', 'wsgi.multiprocess',
-                     'wsgi.run_once', 'wsgi.version',
-                     'wsgi.url_scheme']
-        for name, value in self.environ.items():
-            if name.upper() == name:
-                if value:
-                    cgi_vars[name] = value
-            elif name not in hide_vars:
-                wsgi_vars[name] = value
-        if self.environ['wsgi.version'] != (1, 0):
-            wsgi_vars['wsgi.version'] = self.environ['wsgi.version']
-        proc_desc = tuple([int(bool(self.environ[key]))
-                           for key in ('wsgi.multiprocess',
-                                       'wsgi.multithread',
-                                       'wsgi.run_once')])
-        wsgi_vars['wsgi process'] = self.process_combos[proc_desc]
-        wsgi_vars['application'] = self.middleware.application
-        if 'paste.config' in self.environ:
-            data[('extra', 'Configuration')] = dict(self.environ['paste.config'])
-        return data
-
-    process_combos = {
-        # multiprocess, multithread, run_once
-        (0, 0, 0): 'Non-concurrent server',
-        (0, 1, 0): 'Multithreaded',
-        (1, 0, 0): 'Multiprocess',
-        (1, 1, 0): 'Multi process AND threads (?)',
-        (0, 0, 1): 'Non-concurrent CGI',
-        (0, 1, 1): 'Multithread CGI (?)',
-        (1, 0, 1): 'CGI',
-        (1, 1, 1): 'Multi thread/process CGI (?)',
-        }
-    
-def handle_exception(exc_info, error_stream, html=True,
-                     debug_mode=False,
-                     error_email=None,
-                     error_log=None,
-                     show_exceptions_in_wsgi_errors=False,
-                     error_email_from='errors@localhost',
-                     smtp_server='localhost',
-                     smtp_username=None, 
-                     smtp_password=None, 
-                     smtp_use_tls=False,
-                     error_subject_prefix='',
-                     error_message=None,
-                     simple_html_error=False,
-                     ):
-    """
-    For exception handling outside of a web context
-
-    Use like::
-
-        import sys
-        from paste.exceptions.errormiddleware import handle_exception
-        try:
-            do stuff
-        except:
-            handle_exception(
-                sys.exc_info(), sys.stderr, html=False, ...other config...)
-
-    If you want to report, but not fully catch the exception, call
-    ``raise`` after ``handle_exception``, which (when given no argument)
-    will reraise the exception.
-    """
-    reported = False
-    exc_data = collector.collect_exception(*exc_info)
-    extra_data = ''
-    if error_email:
-        rep = reporter.EmailReporter(
-            to_addresses=error_email,
-            from_address=error_email_from,
-            smtp_server=smtp_server,
-            smtp_username=smtp_username,
-            smtp_password=smtp_password,
-            smtp_use_tls=smtp_use_tls,
-            subject_prefix=error_subject_prefix)
-        rep_err = send_report(rep, exc_data, html=html)
-        if rep_err:
-            extra_data += rep_err
-        else:
-            reported = True
-    if error_log:
-        rep = reporter.LogReporter(
-            filename=error_log)
-        rep_err = send_report(rep, exc_data, html=html)
-        if rep_err:
-            extra_data += rep_err
-        else:
-            reported = True
-    if show_exceptions_in_wsgi_errors:
-        rep = reporter.FileReporter(
-            file=error_stream)
-        rep_err = send_report(rep, exc_data, html=html)
-        if rep_err:
-            extra_data += rep_err
-        else:
-            reported = True
-    else:
-        error_stream.write('Error - %s: %s\n' % (
-            exc_data.exception_type, exc_data.exception_value))
-    if html:
-        if debug_mode and simple_html_error:
-            return_error = formatter.format_html(
-                exc_data, include_hidden_frames=False,
-                include_reusable=False, show_extra_data=False)
-            reported = True
-        elif debug_mode and not simple_html_error:
-            error_html = formatter.format_html(
-                exc_data,
-                include_hidden_frames=True,
-                include_reusable=False)
-            head_html = formatter.error_css + formatter.hide_display_js
-            return_error = error_template(
-                head_html, error_html, extra_data)
-            extra_data = ''
-            reported = True
-        else:
-            msg = error_message or '''
-            An error occurred.  See the error logs for more information.
-            (Turn debug on to display exception reports here)
-            '''
-            return_error = error_template('', msg, '')
-    else:
-        return_error = None
-    if not reported and error_stream:
-        err_report = formatter.format_text(exc_data, show_hidden_frames=True)
-        err_report += '\n' + '-'*60 + '\n'
-        error_stream.write(err_report)
-    if extra_data:
-        error_stream.write(extra_data)
-    return return_error
-
-def send_report(rep, exc_data, html=True):
-    try:
-        rep.report(exc_data)
-    except:
-        output = StringIO()
-        traceback.print_exc(file=output)
-        if html:
-            return """
-            <p>Additionally an error occurred while sending the %s report:
-
-            <pre>%s</pre>
-            </p>""" % (
-                cgi.escape(str(rep)), output.getvalue())
-        else:
-            return (
-                "Additionally an error occurred while sending the "
-                "%s report:\n%s" % (str(rep), output.getvalue()))
-    else:
-        return ''
-
-def error_template(head_html, exception, extra):
-    return '''
-    <html>
-    <head>
-    <title>Server Error</title>
-    %s
-    </head>
-    <body>
-    <h1>Server Error</h1>
-    %s
-    %s
-    </body>
-    </html>''' % (head_html, exception, extra)
-
-def make_error_middleware(app, global_conf, **kw):
-    return ErrorMiddleware(app, global_conf=global_conf, **kw)
-
-doc_lines = ErrorMiddleware.__doc__.splitlines(True)
-for i in range(len(doc_lines)):
-    if doc_lines[i].strip().startswith('Settings'):
-        make_error_middleware.__doc__ = ''.join(doc_lines[i:])
-        break
-del i, doc_lines
diff --git a/lib/paste/exceptions/formatter.py b/lib/paste/exceptions/formatter.py
@@ -1,564 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-"""
-Formatters for the exception data that comes from ExceptionCollector.
-"""
-# @@: TODO:
-# Use this: http://www.zope.org/Members/tino/VisualTraceback/VisualTracebackNews
-
-import cgi
-import re
-from paste.util import PySourceColor
-
-def html_quote(s):
-    return cgi.escape(str(s), True)
-
-class AbstractFormatter(object):
-
-    general_data_order = ['object', 'source_url']
-
-    def __init__(self, show_hidden_frames=False,
-                 include_reusable=True,
-                 show_extra_data=True,
-                 trim_source_paths=()):
-        self.show_hidden_frames = show_hidden_frames
-        self.trim_source_paths = trim_source_paths
-        self.include_reusable = include_reusable
-        self.show_extra_data = show_extra_data
-
-    def format_collected_data(self, exc_data):
-        general_data = {}
-        if self.show_extra_data:
-            for name, value_list in exc_data.extra_data.items():
-                if isinstance(name, tuple):
-                    importance, title = name
-                else:
-                    importance, title = 'normal', name
-                for value in value_list:
-                    general_data[(importance, name)] = self.format_extra_data(
-                        importance, title, value)
-        lines = []
-        frames = self.filter_frames(exc_data.frames)
-        for frame in frames:
-            sup = frame.supplement
-            if sup:
-                if sup.object:
-                    general_data[('important', 'object')] = self.format_sup_object(
-                        sup.object)
-                if sup.source_url:
-                    general_data[('important', 'source_url')] = self.format_sup_url(
-                        sup.source_url)
-                if sup.line:
-                    lines.append(self.format_sup_line_pos(sup.line, sup.column))
-                if sup.expression:
-                    lines.append(self.format_sup_expression(sup.expression))
-                if sup.warnings:
-                    for warning in sup.warnings:
-                        lines.append(self.format_sup_warning(warning))
-                if sup.info:
-                    lines.extend(self.format_sup_info(sup.info))
-            if frame.supplement_exception:
-                lines.append('Exception in supplement:')
-                lines.append(self.quote_long(frame.supplement_exception))
-            if frame.traceback_info:
-                lines.append(self.format_traceback_info(frame.traceback_info))
-            filename = frame.filename
-            if filename and self.trim_source_paths:
-                for path, repl in self.trim_source_paths:
-                    if filename.startswith(path):
-                        filename = repl + filename[len(path):]
-                        break
-            lines.append(self.format_source_line(filename or '?', frame))
-            source = frame.get_source_line()
-            long_source = frame.get_source_line(2)
-            if source:
-                lines.append(self.format_long_source(
-                    source, long_source))
-        etype = exc_data.exception_type
-        if not isinstance(etype, basestring):
-            etype = etype.__name__
-        exc_info = self.format_exception_info(
-            etype,
-            exc_data.exception_value)
-        data_by_importance = {'important': [], 'normal': [],
-                              'supplemental': [], 'extra': []}
-        for (importance, name), value in general_data.items():
-            data_by_importance[importance].append(
-                (name, value))
-        for value in data_by_importance.values():
-            value.sort()
-        return self.format_combine(data_by_importance, lines, exc_info)
-
-    def filter_frames(self, frames):
-        """
-        Removes any frames that should be hidden, according to the
-        values of traceback_hide, self.show_hidden_frames, and the
-        hidden status of the final frame.
-        """
-        if self.show_hidden_frames:
-            return frames
-        new_frames = []
-        hidden = False
-        for frame in frames:
-            hide = frame.traceback_hide
-            # @@: It would be nice to signal a warning if an unknown
-            # hide string was used, but I'm not sure where to put
-            # that warning.
-            if hide == 'before':
-                new_frames = []
-                hidden = False
-            elif hide == 'before_and_this':
-                new_frames = []
-                hidden = False
-                continue
-            elif hide == 'reset':
-                hidden = False
-            elif hide == 'reset_and_this':
-                hidden = False
-                continue
-            elif hide == 'after':
-                hidden = True
-            elif hide == 'after_and_this':
-                hidden = True
-                continue
-            elif hide:
-                continue
-            elif hidden:
-                continue
-            new_frames.append(frame)
-        if frames[-1] not in new_frames:
-            # We must include the last frame; that we don't indicates
-            # that the error happened where something was "hidden",
-            # so we just have to show everything
-            return frames
-        return new_frames
-
-    def pretty_string_repr(self, s):
-        """
-        Formats the string as a triple-quoted string when it contains
-        newlines.
-        """
-        if '\n' in s:
-            s = repr(s)
-            s = s[0]*3 + s[1:-1] + s[-1]*3
-            s = s.replace('\\n', '\n')
-            return s
-        else:
-            return repr(s)
-
-    def long_item_list(self, lst):
-        """
-        Returns true if the list contains items that are long, and should
-        be more nicely formatted.
-        """
-        how_many = 0
-        for item in lst:
-            if len(repr(item)) > 40:
-                how_many += 1
-                if how_many >= 3:
-                    return True
-        return False
-
-class TextFormatter(AbstractFormatter):
-
-    def quote(self, s):
-        return s
-    def quote_long(self, s):
-        return s
-    def emphasize(self, s):
-        return s
-    def format_sup_object(self, obj):
-        return 'In object: %s' % self.emphasize(self.quote(repr(obj)))
-    def format_sup_url(self, url):
-        return 'URL: %s' % self.quote(url)
-    def format_sup_line_pos(self, line, column):
-        if column:
-            return self.emphasize('Line %i, Column %i' % (line, column))
-        else:
-            return self.emphasize('Line %i' % line)
-    def format_sup_expression(self, expr):
-        return self.emphasize('In expression: %s' % self.quote(expr))
-    def format_sup_warning(self, warning):
-        return 'Warning: %s' % self.quote(warning)
-    def format_sup_info(self, info):
-        return [self.quote_long(info)]
-    def format_source_line(self, filename, frame):
-        return 'File %r, line %s in %s' % (
-            filename, frame.lineno or '?', frame.name or '?')
-    def format_long_source(self, source, long_source):
-        return self.format_source(source)
-    def format_source(self, source_line):
-        return '  ' + self.quote(source_line.strip())
-    def format_exception_info(self, etype, evalue):
-        return self.emphasize(
-            '%s: %s' % (self.quote(etype), self.quote(evalue)))
-    def format_traceback_info(self, info):
-        return info
-        
-    def format_combine(self, data_by_importance, lines, exc_info):
-        lines[:0] = [value for n, value in data_by_importance['important']]
-        lines.append(exc_info)
-        for name in 'normal', 'supplemental', 'extra':
-            lines.extend([value for n, value in data_by_importance[name]])
-        return self.format_combine_lines(lines)
-
-    def format_combine_lines(self, lines):
-        return '\n'.join(lines)
-
-    def format_extra_data(self, importance, title, value):
-        if isinstance(value, str):
-            s = self.pretty_string_repr(value)
-            if '\n' in s:
-                return '%s:\n%s' % (title, s)
-            else:
-                return '%s: %s' % (title, s)
-        elif isinstance(value, dict):
-            lines = ['\n', title, '-'*len(title)]
-            items = value.items()
-            items.sort()
-            for n, v in items:
-                try:
-                    v = repr(v)
-                except Exception, e:
-                    v = 'Cannot display: %s' % e
-                v = truncate(v)
-                lines.append('  %s: %s' % (n, v))
-            return '\n'.join(lines)
-        elif (isinstance(value, (list, tuple))
-              and self.long_item_list(value)):
-            parts = [truncate(repr(v)) for v in value]
-            return '%s: [\n    %s]' % (
-                title, ',\n    '.join(parts))
-        else:
-            return '%s: %s' % (title, truncate(repr(value)))
-
-class HTMLFormatter(TextFormatter):
-
-    def quote(self, s):
-        return html_quote(s)
-    def quote_long(self, s):
-        return '<pre>%s</pre>' % self.quote(s)
-    def emphasize(self, s):
-        return '<b>%s</b>' % s
-    def format_sup_url(self, url):
-        return 'URL: <a href="%s">%s</a>' % (url, url)
-    def format_combine_lines(self, lines):
-        return '<br>\n'.join(lines)
-    def format_source_line(self, filename, frame):
-        name = self.quote(frame.name or '?')
-        return 'Module <span class="module" title="%s">%s</span>:<b>%s</b> in <code>%s</code>' % (
-            filename, frame.modname or '?', frame.lineno or '?',
-            name)
-        return 'File %r, line %s in <tt>%s</tt>' % (
-            filename, frame.lineno, name)
-    def format_long_source(self, source, long_source):
-        q_long_source = str2html(long_source, False, 4, True)
-        q_source = str2html(source, True, 0, False)
-        return ('<code style="display: none" class="source" source-type="long"><a class="switch_source" onclick="return switch_source(this, \'long\')" href="#">&lt;&lt;&nbsp; </a>%s</code>'
-                '<code class="source" source-type="short"><a onclick="return switch_source(this, \'short\')" class="switch_source" href="#">&gt;&gt;&nbsp; </a>%s</code>'
-                % (q_long_source,
-                   q_source))
-    def format_source(self, source_line):
-        return '&nbsp;&nbsp;<code class="source">%s</code>' % self.quote(source_line.strip())
-    def format_traceback_info(self, info):
-        return '<pre>%s</pre>' % self.quote(info)
-
-    def format_extra_data(self, importance, title, value):
-        if isinstance(value, str):
-            s = self.pretty_string_repr(value)
-            if '\n' in s:
-                return '%s:<br><pre>%s</pre>' % (title, self.quote(s))
-            else:
-                return '%s: <tt>%s</tt>' % (title, self.quote(s))
-        elif isinstance(value, dict):
-            return self.zebra_table(title, value)
-        elif (isinstance(value, (list, tuple))
-              and self.long_item_list(value)):
-            return '%s: <tt>[<br>\n&nbsp; &nbsp; %s]</tt>' % (
-                title, ',<br>&nbsp; &nbsp; '.join(map(self.quote, map(repr, value))))
-        else:
-            return '%s: <tt>%s</tt>' % (title, self.quote(repr(value)))
-
-    def format_combine(self, data_by_importance, lines, exc_info):
-        lines[:0] = [value for n, value in data_by_importance['important']]
-        lines.append(exc_info)
-        for name in 'normal', 'supplemental':
-            lines.extend([value for n, value in data_by_importance[name]])
-        if data_by_importance['extra']:
-            lines.append(
-                '<script type="text/javascript">\nshow_button(\'extra_data\', \'extra data\');\n</script>\n' +
-                '<div id="extra_data" class="hidden-data">\n')
-            lines.extend([value for n, value in data_by_importance['extra']])
-            lines.append('</div>')
-        text = self.format_combine_lines(lines)
-        if self.include_reusable:
-            return error_css + hide_display_js + text
-        else:
-            # Usually because another error is already on this page,
-            # and so the js & CSS are unneeded
-            return text
-
-    def zebra_table(self, title, rows, table_class="variables"):
-        if isinstance(rows, dict):
-            rows = rows.items()
-            rows.sort()
-        table = ['<table class="%s">' % table_class,
-                 '<tr class="header"><th colspan="2">%s</th></tr>'
-                 % self.quote(title)]
-        odd = False
-        for name, value in rows:
-            try:
-                value = repr(value)
-            except Exception, e:
-                value = 'Cannot print: %s' % e
-            odd = not odd
-            table.append(
-                '<tr class="%s"><td>%s</td>'
-                % (odd and 'odd' or 'even', self.quote(name)))
-            table.append(
-                '<td><tt>%s</tt></td></tr>'
-                % make_wrappable(self.quote(truncate(value))))
-        table.append('</table>')
-        return '\n'.join(table)
-
-hide_display_js = r'''
-<script type="text/javascript">
-function hide_display(id) {
-    var el = document.getElementById(id);
-    if (el.className == "hidden-data") {
-        el.className = "";
-        return true;
-    } else {
-        el.className = "hidden-data";
-        return false;
-    }
-}
-document.write('<style type="text/css">\n');
-document.write('.hidden-data {display: none}\n');
-document.write('</style>\n');
-function show_button(toggle_id, name) {
-    document.write('<a href="#' + toggle_id
-        + '" onclick="javascript:hide_display(\'' + toggle_id
-        + '\')" class="button">' + name + '</a><br>');
-}
-
-function switch_source(el, hide_type) {
-    while (el) {
-        if (el.getAttribute &&
-            el.getAttribute('source-type') == hide_type) {
-            break;
-        }
-        el = el.parentNode;
-    }
-    if (! el) {
-        return false;
-    }
-    el.style.display = 'none';
-    if (hide_type == 'long') {
-        while (el) {
-            if (el.getAttribute &&
-                el.getAttribute('source-type') == 'short') {
-                break;
-            }
-            el = el.nextSibling;
-        }
-    } else {
-        while (el) {
-            if (el.getAttribute &&
-                el.getAttribute('source-type') == 'long') {
-                break;
-            }
-            el = el.previousSibling;
-        }
-    }
-    if (el) {
-        el.style.display = '';
-    }
-    return false;
-}
-
-</script>'''
-    
-
-error_css = """
-<style type="text/css">
-body {
-  font-family: Helvetica, sans-serif;
-}
-
-table {
-  width: 100%;
-}
-
-tr.header {
-  background-color: #006;
-  color: #fff;
-}
-
-tr.even {
-  background-color: #ddd;
-}
-
-table.variables td {
-  vertical-align: top;
-  overflow: auto;
-}
-
-a.button {
-  background-color: #ccc;
-  border: 2px outset #aaa;
-  color: #000;
-  text-decoration: none;
-}
-
-a.button:hover {
-  background-color: #ddd;
-}
-
-code.source {
-  color: #006;
-}
-
-a.switch_source {
-  color: #090;
-  text-decoration: none;
-}
-
-a.switch_source:hover {
-  background-color: #ddd;
-}
-
-.source-highlight {
-  background-color: #ff9;
-}
-
-</style>
-"""
-
-def format_html(exc_data, include_hidden_frames=False, **ops):
-    if not include_hidden_frames:
-        return HTMLFormatter(**ops).format_collected_data(exc_data)
-    short_er = format_html(exc_data, show_hidden_frames=False, **ops)
-    # @@: This should have a way of seeing if the previous traceback
-    # was actually trimmed at all
-    ops['include_reusable'] = False
-    ops['show_extra_data'] = False
-    long_er = format_html(exc_data, show_hidden_frames=True, **ops)
-    text_er = format_text(exc_data, show_hidden_frames=True, **ops)
-    return """
-    %s
-    <br>
-    <script type="text/javascript">
-    show_button('full_traceback', 'full traceback')
-    </script>
-    <div id="full_traceback" class="hidden-data">
-    %s
-    </div>
-    <br>
-    <script type="text/javascript">
-    show_button('text_version', 'text version')
-    </script>
-    <div id="text_version" class="hidden-data">
-    <textarea style="width: 100%%" rows=10 cols=60>%s</textarea>
-    </div>
-    """ % (short_er, long_er, cgi.escape(text_er))
-        
-def format_text(exc_data, **ops):
-    return TextFormatter(**ops).format_collected_data(exc_data)
-
-whitespace_re = re.compile(r'  +')
-pre_re = re.compile(r'</?pre.*?>')
-error_re = re.compile(r'<h3>ERROR: .*?</h3>')
-
-def str2html(src, strip=False, indent_subsequent=0,
-             highlight_inner=False):
-    """
-    Convert a string to HTML.  Try to be really safe about it,
-    returning a quoted version of the string if nothing else works.
-    """
-    try:
-        return _str2html(src, strip=strip,
-                         indent_subsequent=indent_subsequent,
-                         highlight_inner=highlight_inner)
-    except:
-        return html_quote(src)
-
-def _str2html(src, strip=False, indent_subsequent=0,
-              highlight_inner=False):
-    if strip:
-        src = src.strip()
-    orig_src = src
-    try:
-        src = PySourceColor.str2html(src, form='snip')
-        src = error_re.sub('', src)
-        src = pre_re.sub('', src)
-        src = re.sub(r'^[\n\r]{0,1}', '', src)
-        src = re.sub(r'[\n\r]{0,1}$', '', src)
-    except:
-        src = html_quote(orig_src)
-    lines = src.splitlines()
-    if len(lines) == 1:
-        return lines[0]
-    indent = ' '*indent_subsequent
-    for i in range(1, len(lines)):
-        lines[i] = indent+lines[i]
-        if highlight_inner and i == len(lines)/2:
-            lines[i] = '<span class="source-highlight">%s</span>' % lines[i]
-    src = '<br>\n'.join(lines)
-    src = whitespace_re.sub(
-        lambda m: '&nbsp;'*(len(m.group(0))-1) + ' ', src)
-    return src
-
-def truncate(string, limit=1000):
-    """
-    Truncate the string to the limit number of
-    characters
-    """
-    if len(string) > limit:
-        return string[:limit-20]+'...'+string[-17:]
-    else:
-        return string
-
-def make_wrappable(html, wrap_limit=60,
-                   split_on=';?&@!$#-/\\"\''):
-    # Currently using <wbr>, maybe should use &#8203;
-    #   http://www.cs.tut.fi/~jkorpela/html/nobr.html
-    if len(html) <= wrap_limit:
-        return html
-    words = html.split()
-    new_words = []
-    for word in words:
-        wrapped_word = ''
-        while len(word) > wrap_limit:
-            for char in split_on:
-                if char in word:
-                    first, rest = word.split(char, 1)
-                    wrapped_word += first+char+'<wbr>'
-                    word = rest
-                    break
-            else:
-                for i in range(0, len(word), wrap_limit):
-                    wrapped_word += word[i:i+wrap_limit]+'<wbr>'
-                word = ''
-        wrapped_word += word
-        new_words.append(wrapped_word)
-    return ' '.join(new_words)
-
-def make_pre_wrappable(html, wrap_limit=60,
-                       split_on=';?&@!$#-/\\"\''):
-    """
-    Like ``make_wrappable()`` but intended for text that will
-    go in a ``<pre>`` block, so wrap on a line-by-line basis.
-    """
-    lines = html.splitlines()
-    new_lines = []
-    for line in lines:
-        if len(line) > wrap_limit:
-            for char in split_on:
-                if char in line:
-                    parts = line.split(char)
-                    line = '<wbr>'.join(parts)
-                    break
-        new_lines.append(line)
-    return '\n'.join(lines)
diff --git a/lib/paste/exceptions/reporter.py b/lib/paste/exceptions/reporter.py
@@ -1,142 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-from email.MIMEText import MIMEText
-from email.MIMEMultipart import MIMEMultipart
-import smtplib
-import time
-try:
-    from socket import sslerror
-except ImportError:
-    sslerror = None
-from paste.exceptions import formatter
-
-class Reporter(object):
-
-    def __init__(self, **conf):
-        for name, value in conf.items():
-            if not hasattr(self, name):
-                raise TypeError(
-                    "The keyword argument %s was not expected"
-                    % name)
-            setattr(self, name, value)
-        self.check_params()
-
-    def check_params(self):
-        pass
-
-    def format_date(self, exc_data):
-        return time.strftime('%c', exc_data.date)
-
-    def format_html(self, exc_data, **kw):
-        return formatter.format_html(exc_data, **kw)
-
-    def format_text(self, exc_data, **kw):
-        return formatter.format_text(exc_data, **kw)
-
-class EmailReporter(Reporter):
-
-    to_addresses = None
-    from_address = None
-    smtp_server = 'localhost'
-    smtp_username = None
-    smtp_password = None
-    smtp_use_tls = False
-    subject_prefix = ''
-
-    def report(self, exc_data):
-        msg = self.assemble_email(exc_data)
-        server = smtplib.SMTP(self.smtp_server)
-        if self.smtp_use_tls:
-            server.ehlo()
-            server.starttls()
-            server.ehlo()
-        if self.smtp_username and self.smtp_password:
-            server.login(self.smtp_username, self.smtp_password)
-        server.sendmail(self.from_address,
-                        self.to_addresses, msg.as_string())
-        try:
-            server.quit()
-        except sslerror:
-            # sslerror is raised in tls connections on closing sometimes
-            pass
-
-    def check_params(self):
-        if not self.to_addresses:
-            raise ValueError("You must set to_addresses")
-        if not self.from_address:
-            raise ValueError("You must set from_address")
-        if isinstance(self.to_addresses, (str, unicode)):
-            self.to_addresses = [self.to_addresses]
-
-    def assemble_email(self, exc_data):
-        short_html_version = self.format_html(
-            exc_data, show_hidden_frames=False)
-        long_html_version = self.format_html(
-            exc_data, show_hidden_frames=True)
-        text_version = self.format_text(
-            exc_data, show_hidden_frames=False)
-        msg = MIMEMultipart()
-        msg.set_type('multipart/alternative')
-        msg.preamble = msg.epilogue = ''
-        text_msg = MIMEText(text_version)
-        text_msg.set_type('text/plain')
-        text_msg.set_param('charset', 'ASCII')
-        msg.attach(text_msg)
-        html_msg = MIMEText(short_html_version)
-        html_msg.set_type('text/html')
-        # @@: Correct character set?
-        html_msg.set_param('charset', 'UTF-8')
-        html_long = MIMEText(long_html_version)
-        html_long.set_type('text/html')
-        html_long.set_param('charset', 'UTF-8')
-        msg.attach(html_msg)
-        msg.attach(html_long)
-        subject = '%s: %s' % (exc_data.exception_type,
-                              formatter.truncate(str(exc_data.exception_value)))
-        msg['Subject'] = self.subject_prefix + subject
-        msg['From'] = self.from_address
-        msg['To'] = ', '.join(self.to_addresses)
-        return msg
-
-class LogReporter(Reporter):
-
-    filename = None
-    show_hidden_frames = True
-
-    def check_params(self):
-        assert self.filename is not None, (
-            "You must give a filename")
-
-    def report(self, exc_data):
-        text = self.format_text(
-            exc_data, show_hidden_frames=self.show_hidden_frames)
-        f = open(self.filename, 'a')
-        try:
-            f.write(text + '\n' + '-'*60 + '\n')
-        finally:
-            f.close()
-
-class FileReporter(Reporter):
-
-    file = None
-    show_hidden_frames = True
-
-    def check_params(self):
-        assert self.file is not None, (
-            "You must give a file object")
-
-    def report(self, exc_data):
-        text = self.format_text(
-            exc_data, show_hidden_frames=self.show_hidden_frames)
-        print text
-        self.file.write(text + '\n' + '-'*60 + '\n')
-
-class WSGIAppReporter(Reporter):
-
-    def __init__(self, exc_data):
-        self.exc_data = exc_data
-
-    def __call__(self, environ, start_response):
-        start_response('500 Server Error', [('Content-type', 'text/html')])
-        return [formatter.format_html(self.exc_data)]
diff --git a/lib/paste/exceptions/serial_number_generator.py b/lib/paste/exceptions/serial_number_generator.py
@@ -1,123 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-"""
-Creates a human-readable identifier, using numbers and digits,
-avoiding ambiguous numbers and letters.  hash_identifier can be used
-to create compact representations that are unique for a certain string
-(or concatenation of strings)
-"""
-
-try:
-    from hashlib import md5
-except ImportError:
-    from md5 import md5
-
-good_characters = "23456789abcdefghjkmnpqrtuvwxyz"
-
-base = len(good_characters)
-
-def make_identifier(number):
-    """
-    Encodes a number as an identifier.
-    """
-    if not isinstance(number, (int, long)):
-        raise ValueError(
-            "You can only make identifiers out of integers (not %r)"
-            % number)
-    if number < 0:
-        raise ValueError(
-            "You cannot make identifiers out of negative numbers: %r"
-            % number)
-    result = []
-    while number:
-        next = number % base
-        result.append(good_characters[next])
-        # Note, this depends on integer rounding of results:
-        number = number / base
-    return ''.join(result)
-
-def hash_identifier(s, length, pad=True, hasher=md5, prefix='',
-                    group=None, upper=False):
-    """
-    Hashes the string (with the given hashing module), then turns that
-    hash into an identifier of the given length (using modulo to
-    reduce the length of the identifier).  If ``pad`` is False, then
-    the minimum-length identifier will be used; otherwise the
-    identifier will be padded with 0's as necessary.
-
-    ``prefix`` will be added last, and does not count towards the
-    target length.  ``group`` will group the characters with ``-`` in
-    the given lengths, and also does not count towards the target
-    length.  E.g., ``group=4`` will cause a identifier like
-    ``a5f3-hgk3-asdf``.  Grouping occurs before the prefix.
-    """
-    if not callable(hasher):
-        # Accept sha/md5 modules as well as callables
-        hasher = hasher.new
-    if length > 26 and hasher is md5:
-        raise ValueError, (
-            "md5 cannot create hashes longer than 26 characters in "
-            "length (you gave %s)" % length)
-    if isinstance(s, unicode):
-        s = s.encode('utf-8')
-    h = hasher(str(s))
-    bin_hash = h.digest()
-    modulo = base ** length
-    number = 0
-    for c in list(bin_hash):
-        number = (number * 256 + ord(c)) % modulo
-    ident = make_identifier(number)
-    if pad:
-        ident = good_characters[0]*(length-len(ident)) + ident
-    if group:
-        parts = []
-        while ident:
-            parts.insert(0, ident[-group:])
-            ident = ident[:-group]
-        ident = '-'.join(parts)
-    if upper:
-        ident = ident.upper()
-    return prefix + ident
-
-# doctest tests:
-__test__ = {
-    'make_identifier': """
-    >>> make_identifier(0)
-    ''
-    >>> make_identifier(1000)
-    'c53'
-    >>> make_identifier(-100)
-    Traceback (most recent call last):
-        ...
-    ValueError: You cannot make identifiers out of negative numbers: -100
-    >>> make_identifier('test')
-    Traceback (most recent call last):
-        ...
-    ValueError: You can only make identifiers out of integers (not 'test')
-    >>> make_identifier(1000000000000)
-    'c53x9rqh3'
-    """,
-    'hash_identifier': """
-    >>> hash_identifier(0, 5)
-    'cy2dr'
-    >>> hash_identifier(0, 10)
-    'cy2dr6rg46'
-    >>> hash_identifier('this is a test of a long string', 5)
-    'awatu'
-    >>> hash_identifier(0, 26)
-    'cy2dr6rg46cx8t4w2f3nfexzk4'
-    >>> hash_identifier(0, 30)
-    Traceback (most recent call last):
-        ...
-    ValueError: md5 cannot create hashes longer than 26 characters in length (you gave 30)
-    >>> hash_identifier(0, 10, group=4)
-    'cy-2dr6-rg46'
-    >>> hash_identifier(0, 10, group=4, upper=True, prefix='M-')
-    'M-CY-2DR6-RG46'
-    """}
-
-if __name__ == '__main__':
-    import doctest
-    doctest.testmod()
-    
diff --git a/lib/paste/fileapp.py b/lib/paste/fileapp.py
@@ -1,349 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-# (c) 2005 Ian Bicking, Clark C. Evans and contributors
-# This module is part of the Python Paste Project and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-"""
-This module handles sending static content such as in-memory data or
-files.  At this time it has cache helpers and understands the
-if-modified-since request header.
-"""
-
-import os, time, mimetypes, zipfile, tarfile
-from paste.httpexceptions import *
-from paste.httpheaders import *
-
-CACHE_SIZE = 4096
-BLOCK_SIZE = 4096 * 16
-
-__all__ = ['DataApp', 'FileApp', 'DirectoryApp', 'ArchiveStore']
-
-class DataApp(object):
-    """
-    Returns an application that will send content in a single chunk,
-    this application has support for setting cache-control and for
-    responding to conditional (or HEAD) requests.
-
-    Constructor Arguments:
-
-        ``content``     the content being sent to the client
-
-        ``headers``     the headers to send /w the response
-
-        The remaining ``kwargs`` correspond to headers, where the
-        underscore is replaced with a dash.  These values are only
-        added to the headers if they are not already provided; thus,
-        they can be used for default values.  Examples include, but
-        are not limited to:
-
-            ``content_type``
-            ``content_encoding``
-            ``content_location``
-
-    ``cache_control()``
-
-        This method provides validated construction of the ``Cache-Control``
-        header as well as providing for automated filling out of the
-        ``EXPIRES`` header for HTTP/1.0 clients.
-
-    ``set_content()``
-
-        This method provides a mechanism to set the content after the
-        application has been constructed.  This method does things
-        like changing ``Last-Modified`` and ``Content-Length`` headers.
-
-    """
-
-    allowed_methods = ('GET', 'HEAD')
-
-    def __init__(self, content, headers=None, allowed_methods=None,
-                 **kwargs):
-        assert isinstance(headers, (type(None), list))
-        self.expires = None
-        self.content = None
-        self.content_length = None
-        self.last_modified = 0
-        if allowed_methods is not None:
-            self.allowed_methods = allowed_methods
-        self.headers = headers or []
-        for (k, v) in kwargs.items():
-            header = get_header(k)
-            header.update(self.headers, v)
-        ACCEPT_RANGES.update(self.headers, bytes=True)
-        if not CONTENT_TYPE(self.headers):
-            CONTENT_TYPE.update(self.headers)
-        if content is not None:
-            self.set_content(content)
-
-    def cache_control(self, **kwargs):
-        self.expires = CACHE_CONTROL.apply(self.headers, **kwargs) or None
-        return self
-
-    def set_content(self, content, last_modified=None):
-        assert content is not None
-        if last_modified is None:
-            self.last_modified = time.time()
-        else:
-            self.last_modified = last_modified
-        self.content = content
-        self.content_length = len(content)
-        LAST_MODIFIED.update(self.headers, time=self.last_modified)
-        return self
-
-    def content_disposition(self, **kwargs):
-        CONTENT_DISPOSITION.apply(self.headers, **kwargs)
-        return self
-
-    def __call__(self, environ, start_response):
-        method = environ['REQUEST_METHOD'].upper()
-        if method not in self.allowed_methods:
-            exc = HTTPMethodNotAllowed(
-                'You cannot %s a file' % method,
-                headers=[('Allow', ','.join(self.allowed_methods))])
-            return exc(environ, start_response)
-        return self.get(environ, start_response)
-
-    def calculate_etag(self):
-        return str(self.last_modified) + '-' + str(self.content_length)
-
-    def get(self, environ, start_response):
-        headers = self.headers[:]
-        current_etag = self.calculate_etag()
-        ETAG.update(headers, current_etag)
-        if self.expires is not None:
-            EXPIRES.update(headers, delta=self.expires)
-
-        try:
-            client_etags = IF_NONE_MATCH.parse(environ)
-            if client_etags:
-                for etag in client_etags:
-                    if etag == current_etag or etag == '*':
-                        # horribly inefficient, n^2 performance, yuck!
-                        for head in list_headers(entity=True):
-                            head.delete(headers)
-                        start_response('304 Not Modified', headers)
-                        return ['']
-        except HTTPBadRequest, exce:
-            return exce.wsgi_application(environ, start_response)
-
-        # If we get If-None-Match and If-Modified-Since, and
-        # If-None-Match doesn't match, then we should not try to
-        # figure out If-Modified-Since (which has 1-second granularity
-        # and just isn't as accurate)
-        if not client_etags:
-            try:
-                client_clock = IF_MODIFIED_SINCE.parse(environ)
-                if client_clock >= int(self.last_modified):
-                    # horribly inefficient, n^2 performance, yuck!
-                    for head in list_headers(entity=True):
-                        head.delete(headers)
-                    start_response('304 Not Modified', headers)
-                    return [''] # empty body
-            except HTTPBadRequest, exce:
-                return exce.wsgi_application(environ, start_response)
-
-        (lower, upper) = (0, self.content_length - 1)
-        range = RANGE.parse(environ)
-        if range and 'bytes' == range[0] and 1 == len(range[1]):
-            (lower, upper) = range[1][0]
-            upper = upper or (self.content_length - 1)
-            if upper >= self.content_length or lower > upper:
-                return HTTPRequestRangeNotSatisfiable((
-                  "Range request was made beyond the end of the content,\r\n"
-                  "which is %s long.\r\n  Range: %s\r\n") % (
-                     self.content_length, RANGE(environ))
-                ).wsgi_application(environ, start_response)
-
-        content_length = upper - lower + 1
-        CONTENT_RANGE.update(headers, first_byte=lower, last_byte=upper,
-                            total_length = self.content_length)
-        CONTENT_LENGTH.update(headers, content_length)
-        if content_length == self.content_length:
-            start_response('200 OK', headers)
-        else:
-            start_response('206 Partial Content', headers)
-        if self.content is not None:
-            return [self.content[lower:upper+1]]
-        return (lower, content_length)
-
-class FileApp(DataApp):
-    """
-    Returns an application that will send the file at the given
-    filename.  Adds a mime type based on ``mimetypes.guess_type()``.
-    See DataApp for the arguments beyond ``filename``.
-    """
-
-    def __init__(self, filename, headers=None, **kwargs):
-        self.filename = filename
-        content_type, content_encoding = self.guess_type()
-        if content_type and 'content_type' not in kwargs:
-            kwargs['content_type'] = content_type
-        if content_encoding and 'content_encoding' not in kwargs:
-            kwargs['content_encoding'] = content_encoding
-        DataApp.__init__(self, None, headers, **kwargs)
-
-    def guess_type(self):
-        return mimetypes.guess_type(self.filename)
-
-    def update(self, force=False):
-        stat = os.stat(self.filename)
-        if not force and stat.st_mtime == self.last_modified:
-            return
-        self.last_modified = stat.st_mtime
-        if stat.st_size < CACHE_SIZE:
-            fh = open(self.filename,"rb")
-            self.set_content(fh.read(), stat.st_mtime)
-            fh.close()
-        else:
-            self.content = None
-            self.content_length = stat.st_size
-            # This is updated automatically if self.set_content() is
-            # called
-            LAST_MODIFIED.update(self.headers, time=self.last_modified)
-
-    def get(self, environ, start_response):
-        is_head = environ['REQUEST_METHOD'].upper() == 'HEAD'
-        if 'max-age=0' in CACHE_CONTROL(environ).lower():
-            self.update(force=True) # RFC 2616 13.2.6
-        else:
-            self.update()
-        if not self.content:
-            if not os.path.exists(self.filename):
-                exc = HTTPNotFound(
-                    'The resource does not exist',
-                    comment="No file at %r" % self.filename)
-                return exc(environ, start_response)
-            try:
-                file = open(self.filename, 'rb')
-            except (IOError, OSError), e:
-                exc = HTTPForbidden(
-                    'You are not permitted to view this file (%s)' % e)
-                return exc.wsgi_application(
-                    environ, start_response)
-        retval = DataApp.get(self, environ, start_response)
-        if isinstance(retval, list):
-            # cached content, exception, or not-modified
-            if is_head:
-                return ['']
-            return retval
-        (lower, content_length) = retval
-        if is_head:
-            return ['']
-        file.seek(lower)
-        file_wrapper = environ.get('wsgi.file_wrapper', None)
-        if file_wrapper:
-            return file_wrapper(file, BLOCK_SIZE)
-        else:
-            return _FileIter(file, size=content_length)
-
-class _FileIter(object):
-
-    def __init__(self, file, block_size=None, size=None):
-        self.file = file
-        self.size = size
-        self.block_size = block_size or BLOCK_SIZE
-
-    def __iter__(self):
-        return self
-
-    def next(self):
-        chunk_size = self.block_size
-        if self.size is not None:
-            if chunk_size > self.size:
-                chunk_size = self.size
-            self.size -= chunk_size
-        data = self.file.read(chunk_size)
-        if not data:
-            raise StopIteration
-        return data
-
-    def close(self):
-        self.file.close()
-
-
-class DirectoryApp(object):
-    """
-    Returns an application that dispatches requests to corresponding FileApps based on PATH_INFO.
-    FileApp instances are cached. This app makes sure not to serve any files that are not in a subdirectory.
-    To customize FileApp creation override ``DirectoryApp.make_fileapp``
-    """
-
-    def __init__(self, path):
-        self.path = os.path.abspath(path)
-        if not self.path.endswith(os.path.sep):
-            self.path += os.path.sep
-        assert os.path.isdir(self.path)
-        self.cached_apps = {}
-
-    make_fileapp = FileApp
-
-    def __call__(self, environ, start_response):
-        path_info = environ['PATH_INFO']
-        app = self.cached_apps.get(path_info)
-        if app is None:
-            path = os.path.join(self.path, path_info.lstrip('/'))
-            if not os.path.normpath(path).startswith(self.path):
-                app = HTTPForbidden()
-            elif os.path.isfile(path):
-                app = self.make_fileapp(path)
-                self.cached_apps[path_info] = app
-            else:
-                app = HTTPNotFound(comment=path)
-        return app(environ, start_response)
-
-
-class ArchiveStore(object):
-    """
-    Returns an application that serves up a DataApp for items requested
-    in a given zip or tar archive.
-
-    Constructor Arguments:
-
-        ``filepath``    the path to the archive being served
-
-    ``cache_control()``
-
-        This method provides validated construction of the ``Cache-Control``
-        header as well as providing for automated filling out of the
-        ``EXPIRES`` header for HTTP/1.0 clients.
-    """
-
-    def __init__(self, filepath):
-        if zipfile.is_zipfile(filepath):
-            self.archive = zipfile.ZipFile(filepath,"r")
-        elif tarfile.is_tarfile(filepath):
-            self.archive = tarfile.TarFileCompat(filepath,"r")
-        else:
-            raise AssertionError("filepath '%s' is not a zip or tar " % filepath)
-        self.expires = None
-        self.last_modified = time.time()
-        self.cache = {}
-
-    def cache_control(self, **kwargs):
-        self.expires = CACHE_CONTROL.apply(self.headers, **kwargs) or None
-        return self
-
-    def __call__(self, environ, start_response):
-        path = environ.get("PATH_INFO","")
-        if path.startswith("/"):
-            path = path[1:]
-        application = self.cache.get(path)
-        if application:
-            return application(environ, start_response)
-        try:
-            info = self.archive.getinfo(path)
-        except KeyError:
-            exc = HTTPNotFound("The file requested, '%s', was not found." % path)
-            return exc.wsgi_application(environ, start_response)
-        if info.filename.endswith("/"):
-            exc = HTTPNotFound("Path requested, '%s', is not a file." % path)
-            return exc.wsgi_application(environ, start_response)
-        content_type, content_encoding = mimetypes.guess_type(info.filename)
-        app = DataApp(None, content_type = content_type,
-                            content_encoding = content_encoding)
-        app.set_content(self.archive.read(path),
-                time.mktime(info.date_time + (0,0,0)))
-        self.cache[path] = app
-        app.expires = self.expires
-        return app(environ, start_response)
-
diff --git a/lib/paste/fixture.py b/lib/paste/fixture.py
@@ -1,1723 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-Routines for testing WSGI applications.
-
-Most interesting is the `TestApp <class-paste.fixture.TestApp.html>`_
-for testing WSGI applications, and the `TestFileEnvironment
-<class-paste.fixture.TestFileEnvironment.html>`_ class for testing the
-effects of command-line scripts.
-"""
-
-import sys
-import random
-import urllib
-import urlparse
-import mimetypes
-import time
-import cgi
-import os
-import shutil
-import smtplib
-import shlex
-from Cookie import BaseCookie
-try:
-    from cStringIO import StringIO
-except ImportError:
-    from StringIO import StringIO
-import re
-try:
-    import subprocess
-except ImportError:
-    from paste.util import subprocess24 as subprocess
-
-from paste import wsgilib
-from paste import lint
-from paste.response import HeaderDict
-
-def tempnam_no_warning(*args):
-    """
-    An os.tempnam with the warning turned off, because sometimes
-    you just need to use this and don't care about the stupid
-    security warning.
-    """
-    return os.tempnam(*args)
-
-class NoDefault(object):
-    pass
-
-def sorted(l):
-    l = list(l)
-    l.sort()
-    return l
-
-class Dummy_smtplib(object):
-
-    existing = None
-
-    def __init__(self, server):
-        import warnings
-        warnings.warn(
-            'Dummy_smtplib is not maintained and is deprecated',
-            DeprecationWarning, 2)
-        assert not self.existing, (
-            "smtplib.SMTP() called again before Dummy_smtplib.existing.reset() "
-            "called.")
-        self.server = server
-        self.open = True
-        self.__class__.existing = self
-
-    def quit(self):
-        assert self.open, (
-            "Called %s.quit() twice" % self)
-        self.open = False
-
-    def sendmail(self, from_address, to_addresses, msg):
-        self.from_address = from_address
-        self.to_addresses = to_addresses
-        self.message = msg
-
-    def install(cls):
-        smtplib.SMTP = cls
-
-    install = classmethod(install)
-
-    def reset(self):
-        assert not self.open, (
-            "SMTP connection not quit")
-        self.__class__.existing = None
-
-class AppError(Exception):
-    pass
-
-class TestApp(object):
-
-    # for py.test
-    disabled = True
-
-    def __init__(self, app, namespace=None, relative_to=None,
-                 extra_environ=None, pre_request_hook=None,
-                 post_request_hook=None):
-        """
-        Wraps a WSGI application in a more convenient interface for
-        testing.
-
-        ``app`` may be an application, or a Paste Deploy app
-        URI, like ``'config:filename.ini#test'``.
-
-        ``namespace`` is a dictionary that will be written to (if
-        provided).  This can be used with doctest or some other
-        system, and the variable ``res`` will be assigned everytime
-        you make a request (instead of returning the request).
-
-        ``relative_to`` is a directory, and filenames used for file
-        uploads are calculated relative to this.  Also ``config:``
-        URIs that aren't absolute.
-
-        ``extra_environ`` is a dictionary of values that should go
-        into the environment for each request.  These can provide a
-        communication channel with the application.
-
-        ``pre_request_hook`` is a function to be called prior to
-        making requests (such as ``post`` or ``get``). This function
-        must take one argument (the instance of the TestApp).
-
-        ``post_request_hook`` is a function, similar to
-        ``pre_request_hook``, to be called after requests are made.
-        """
-        if isinstance(app, (str, unicode)):
-            from paste.deploy import loadapp
-            # @@: Should pick up relative_to from calling module's
-            # __file__
-            app = loadapp(app, relative_to=relative_to)
-        self.app = app
-        self.namespace = namespace
-        self.relative_to = relative_to
-        if extra_environ is None:
-            extra_environ = {}
-        self.extra_environ = extra_environ
-        self.pre_request_hook = pre_request_hook
-        self.post_request_hook = post_request_hook
-        self.reset()
-
-    def reset(self):
-        """
-        Resets the state of the application; currently just clears
-        saved cookies.
-        """
-        self.cookies = {}
-
-    def _make_environ(self):
-        environ = self.extra_environ.copy()
-        environ['paste.throw_errors'] = True
-        return environ
-
-    def get(self, url, params=None, headers=None, extra_environ=None,
-            status=None, expect_errors=False):
-        """
-        Get the given url (well, actually a path like
-        ``'/page.html'``).
-
-        ``params``:
-            A query string, or a dictionary that will be encoded
-            into a query string.  You may also include a query
-            string on the ``url``.
-
-        ``headers``:
-            A dictionary of extra headers to send.
-
-        ``extra_environ``:
-            A dictionary of environmental variables that should
-            be added to the request.
-
-        ``status``:
-            The integer status code you expect (if not 200 or 3xx).
-            If you expect a 404 response, for instance, you must give
-            ``status=404`` or it will be an error.  You can also give
-            a wildcard, like ``'3*'`` or ``'*'``.
-
-        ``expect_errors``:
-            If this is not true, then if anything is written to
-            ``wsgi.errors`` it will be an error.  If it is true, then
-            non-200/3xx responses are also okay.
-
-        Returns a `response object
-        <class-paste.fixture.TestResponse.html>`_
-        """
-        if extra_environ is None:
-            extra_environ = {}
-        # Hide from py.test:
-        __tracebackhide__ = True
-        if params:
-            if not isinstance(params, (str, unicode)):
-                params = urllib.urlencode(params, doseq=True)
-            if '?' in url:
-                url += '&'
-            else:
-                url += '?'
-            url += params
-        environ = self._make_environ()
-        url = str(url)
-        if '?' in url:
-            url, environ['QUERY_STRING'] = url.split('?', 1)
-        else:
-            environ['QUERY_STRING'] = ''
-        self._set_headers(headers, environ)
-        environ.update(extra_environ)
-        req = TestRequest(url, environ, expect_errors)
-        return self.do_request(req, status=status)
-
-    def _gen_request(self, method, url, params='', headers=None, extra_environ=None,
-             status=None, upload_files=None, expect_errors=False):
-        """
-        Do a generic request.  
-        """
-        if headers is None:
-            headers = {}
-        if extra_environ is None:
-            extra_environ = {}
-        environ = self._make_environ()
-        # @@: Should this be all non-strings?
-        if isinstance(params, (list, tuple, dict)):
-            params = urllib.urlencode(params)
-        if hasattr(params, 'items'):
-            # Some other multi-dict like format
-            params = urllib.urlencode(params.items())
-        if upload_files:
-            params = cgi.parse_qsl(params, keep_blank_values=True)
-            content_type, params = self.encode_multipart(
-                params, upload_files)
-            environ['CONTENT_TYPE'] = content_type
-        elif params:
-            environ.setdefault('CONTENT_TYPE', 'application/x-www-form-urlencoded')
-        if '?' in url:
-            url, environ['QUERY_STRING'] = url.split('?', 1)
-        else:
-            environ['QUERY_STRING'] = ''
-        environ['CONTENT_LENGTH'] = str(len(params))
-        environ['REQUEST_METHOD'] = method
-        environ['wsgi.input'] = StringIO(params)
-        self._set_headers(headers, environ)
-        environ.update(extra_environ)
-        req = TestRequest(url, environ, expect_errors)
-        return self.do_request(req, status=status)
-
-    def post(self, url, params='', headers=None, extra_environ=None,
-             status=None, upload_files=None, expect_errors=False):
-        """
-        Do a POST request.  Very like the ``.get()`` method.
-        ``params`` are put in the body of the request.
-
-        ``upload_files`` is for file uploads.  It should be a list of
-        ``[(fieldname, filename, file_content)]``.  You can also use
-        just ``[(fieldname, filename)]`` and the file content will be
-        read from disk.
-
-        Returns a `response object
-        <class-paste.fixture.TestResponse.html>`_
-        """
-        return self._gen_request('POST', url, params=params, headers=headers,
-                                 extra_environ=extra_environ,status=status,
-                                 upload_files=upload_files,
-                                 expect_errors=expect_errors)
-
-    def put(self, url, params='', headers=None, extra_environ=None,
-             status=None, upload_files=None, expect_errors=False):
-        """
-        Do a PUT request.  Very like the ``.get()`` method.
-        ``params`` are put in the body of the request.
-
-        ``upload_files`` is for file uploads.  It should be a list of
-        ``[(fieldname, filename, file_content)]``.  You can also use
-        just ``[(fieldname, filename)]`` and the file content will be
-        read from disk.
-
-        Returns a `response object
-        <class-paste.fixture.TestResponse.html>`_
-        """
-        return self._gen_request('PUT', url, params=params, headers=headers,
-                                 extra_environ=extra_environ,status=status,
-                                 upload_files=upload_files,
-                                 expect_errors=expect_errors)
-
-    def delete(self, url, params='', headers=None, extra_environ=None,
-               status=None, expect_errors=False):
-        """
-        Do a DELETE request.  Very like the ``.get()`` method.
-        ``params`` are put in the body of the request.
-
-        Returns a `response object
-        <class-paste.fixture.TestResponse.html>`_
-        """
-        return self._gen_request('DELETE', url, params=params, headers=headers,
-                                 extra_environ=extra_environ,status=status,
-                                 upload_files=None, expect_errors=expect_errors)
-
-    
-
-
-    def _set_headers(self, headers, environ):
-        """
-        Turn any headers into environ variables
-        """
-        if not headers:
-            return
-        for header, value in headers.items():
-            if header.lower() == 'content-type':
-                var = 'CONTENT_TYPE'
-            elif header.lower() == 'content-length':
-                var = 'CONTENT_LENGTH'
-            else:
-                var = 'HTTP_%s' % header.replace('-', '_').upper()
-            environ[var] = value
-
-    def encode_multipart(self, params, files):
-        """
-        Encodes a set of parameters (typically a name/value list) and
-        a set of files (a list of (name, filename, file_body)) into a
-        typical POST body, returning the (content_type, body).
-        """
-        boundary = '----------a_BoUnDaRy%s$' % random.random()
-        lines = []
-        for key, value in params:
-            lines.append('--'+boundary)
-            lines.append('Content-Disposition: form-data; name="%s"' % key)
-            lines.append('')
-            lines.append(value)
-        for file_info in files:
-            key, filename, value = self._get_file_info(file_info)
-            lines.append('--'+boundary)
-            lines.append('Content-Disposition: form-data; name="%s"; filename="%s"'
-                         % (key, filename))
-            fcontent = mimetypes.guess_type(filename)[0]
-            lines.append('Content-Type: %s' %
-                         fcontent or 'application/octet-stream')
-            lines.append('')
-            lines.append(value)
-        lines.append('--' + boundary + '--')
-        lines.append('')
-        body = '\r\n'.join(lines)
-        content_type = 'multipart/form-data; boundary=%s' % boundary
-        return content_type, body
-
-    def _get_file_info(self, file_info):
-        if len(file_info) == 2:
-            # It only has a filename
-            filename = file_info[1]
-            if self.relative_to:
-                filename = os.path.join(self.relative_to, filename)
-            f = open(filename, 'rb')
-            content = f.read()
-            f.close()
-            return (file_info[0], filename, content)
-        elif len(file_info) == 3:
-            return file_info
-        else:
-            raise ValueError(
-                "upload_files need to be a list of tuples of (fieldname, "
-                "filename, filecontent) or (fieldname, filename); "
-                "you gave: %r"
-                % repr(file_info)[:100])
-
-    def do_request(self, req, status):
-        """
-        Executes the given request (``req``), with the expected
-        ``status``.  Generally ``.get()`` and ``.post()`` are used
-        instead.
-        """
-        if self.pre_request_hook:
-            self.pre_request_hook(self)
-        __tracebackhide__ = True
-        if self.cookies:
-            c = BaseCookie()
-            for name, value in self.cookies.items():
-                c[name] = value
-            hc = '; '.join(['='.join([m.key, m.value]) for m in c.values()])
-            req.environ['HTTP_COOKIE'] = hc
-        req.environ['paste.testing'] = True
-        req.environ['paste.testing_variables'] = {}
-        app = lint.middleware(self.app)
-        old_stdout = sys.stdout
-        out = CaptureStdout(old_stdout)
-        try:
-            sys.stdout = out
-            start_time = time.time()
-            raise_on_wsgi_error = not req.expect_errors
-            raw_res = wsgilib.raw_interactive(
-                app, req.url,
-                raise_on_wsgi_error=raise_on_wsgi_error,
-                **req.environ)
-            end_time = time.time()
-        finally:
-            sys.stdout = old_stdout
-            sys.stderr.write(out.getvalue())
-        res = self._make_response(raw_res, end_time - start_time)
-        res.request = req
-        for name, value in req.environ['paste.testing_variables'].items():
-            if hasattr(res, name):
-                raise ValueError(
-                    "paste.testing_variables contains the variable %r, but "
-                    "the response object already has an attribute by that "
-                    "name" % name)
-            setattr(res, name, value)
-        if self.namespace is not None:
-            self.namespace['res'] = res
-        if not req.expect_errors:
-            self._check_status(status, res)
-            self._check_errors(res)
-        res.cookies_set = {}
-        for header in res.all_headers('set-cookie'):
-            c = BaseCookie(header)
-            for key, morsel in c.items():
-                self.cookies[key] = morsel.value
-                res.cookies_set[key] = morsel.value
-        if self.post_request_hook:
-            self.post_request_hook(self)
-        if self.namespace is None:
-            # It's annoying to return the response in doctests, as it'll
-            # be printed, so we only return it is we couldn't assign
-            # it anywhere
-            return res
-
-    def _check_status(self, status, res):
-        __tracebackhide__ = True
-        if status == '*':
-            return
-        if isinstance(status, (list, tuple)):
-            if res.status not in status:
-                raise AppError(
-                    "Bad response: %s (not one of %s for %s)\n%s"
-                    % (res.full_status, ', '.join(map(str, status)),
-                       res.request.url, res.body))
-            return
-        if status is None:
-            if res.status >= 200 and res.status < 400:
-                return
-            raise AppError(
-                "Bad response: %s (not 200 OK or 3xx redirect for %s)\n%s"
-                % (res.full_status, res.request.url,
-                   res.body))
-        if status != res.status:
-            raise AppError(
-                "Bad response: %s (not %s)" % (res.full_status, status))
-
-    def _check_errors(self, res):
-        if res.errors:
-            raise AppError(
-                "Application had errors logged:\n%s" % res.errors)
-
-    def _make_response(self, (status, headers, body, errors), total_time):
-        return TestResponse(self, status, headers, body, errors,
-                            total_time)
-
-class CaptureStdout(object):
-
-    def __init__(self, actual):
-        self.captured = StringIO()
-        self.actual = actual
-
-    def write(self, s):
-        self.captured.write(s)
-        self.actual.write(s)
-
-    def flush(self):
-        self.actual.flush()
-
-    def writelines(self, lines):
-        for item in lines:
-            self.write(item)
-
-    def getvalue(self):
-        return self.captured.getvalue()
-
-class TestResponse(object):
-
-    # for py.test
-    disabled = True
-
-    """
-    Instances of this class are return by `TestApp
-    <class-paste.fixture.TestApp.html>`_
-    """
-
-    def __init__(self, test_app, status, headers, body, errors,
-                 total_time):
-        self.test_app = test_app
-        self.status = int(status.split()[0])
-        self.full_status = status
-        self.headers = headers
-        self.header_dict = HeaderDict.fromlist(self.headers)
-        self.body = body
-        self.errors = errors
-        self._normal_body = None
-        self.time = total_time
-        self._forms_indexed = None
-
-    def forms__get(self):
-        """
-        Returns a dictionary of ``Form`` objects.  Indexes are both in
-        order (from zero) and by form id (if the form is given an id).
-        """
-        if self._forms_indexed is None:
-            self._parse_forms()
-        return self._forms_indexed
-
-    forms = property(forms__get,
-                     doc="""
-                     A list of <form>s found on the page (instances of
-                     `Form <class-paste.fixture.Form.html>`_)
-                     """)
-
-    def form__get(self):
-        forms = self.forms
-        if not forms:
-            raise TypeError(
-                "You used response.form, but no forms exist")
-        if 1 in forms:
-            # There is more than one form
-            raise TypeError(
-                "You used response.form, but more than one form exists")
-        return forms[0]
-
-    form = property(form__get,
-                    doc="""
-                    Returns a single `Form
-                    <class-paste.fixture.Form.html>`_ instance; it
-                    is an error if there are multiple forms on the
-                    page.
-                    """)
-
-    _tag_re = re.compile(r'<(/?)([:a-z0-9_\-]*)(.*?)>', re.S|re.I)
-
-    def _parse_forms(self):
-        forms = self._forms_indexed = {}
-        form_texts = []
-        started = None
-        for match in self._tag_re.finditer(self.body):
-            end = match.group(1) == '/'
-            tag = match.group(2).lower()
-            if tag != 'form':
-                continue
-            if end:
-                assert started, (
-                    "</form> unexpected at %s" % match.start())
-                form_texts.append(self.body[started:match.end()])
-                started = None
-            else:
-                assert not started, (
-                    "Nested form tags at %s" % match.start())
-                started = match.start()
-        assert not started, (
-            "Danging form: %r" % self.body[started:])
-        for i, text in enumerate(form_texts):
-            form = Form(self, text)
-            forms[i] = form
-            if form.id:
-                forms[form.id] = form
-
-    def header(self, name, default=NoDefault):
-        """
-        Returns the named header; an error if there is not exactly one
-        matching header (unless you give a default -- always an error
-        if there is more than one header)
-        """
-        found = None
-        for cur_name, value in self.headers:
-            if cur_name.lower() == name.lower():
-                assert not found, (
-                    "Ambiguous header: %s matches %r and %r"
-                    % (name, found, value))
-                found = value
-        if found is None:
-            if default is NoDefault:
-                raise KeyError(
-                    "No header found: %r (from %s)"
-                    % (name, ', '.join([n for n, v in self.headers])))
-            else:
-                return default
-        return found
-
-    def all_headers(self, name):
-        """
-        Gets all headers by the ``name``, returns as a list
-        """
-        found = []
-        for cur_name, value in self.headers:
-            if cur_name.lower() == name.lower():
-                found.append(value)
-        return found
-
-    def follow(self, **kw):
-        """
-        If this request is a redirect, follow that redirect.  It
-        is an error if this is not a redirect response.  Returns
-        another response object.
-        """
-        assert self.status >= 300 and self.status < 400, (
-            "You can only follow redirect responses (not %s)"
-            % self.full_status)
-        location = self.header('location')
-        type, rest = urllib.splittype(location)
-        host, path = urllib.splithost(rest)
-        # @@: We should test that it's not a remote redirect
-        return self.test_app.get(location, **kw)
-
-    def click(self, description=None, linkid=None, href=None,
-              anchor=None, index=None, verbose=False):
-        """
-        Click the link as described.  Each of ``description``,
-        ``linkid``, and ``url`` are *patterns*, meaning that they are
-        either strings (regular expressions), compiled regular
-        expressions (objects with a ``search`` method), or callables
-        returning true or false.
-
-        All the given patterns are ANDed together:
-
-        * ``description`` is a pattern that matches the contents of the
-          anchor (HTML and all -- everything between ``<a...>`` and
-          ``</a>``)
-
-        * ``linkid`` is a pattern that matches the ``id`` attribute of
-          the anchor.  It will receive the empty string if no id is
-          given.
-
-        * ``href`` is a pattern that matches the ``href`` of the anchor;
-          the literal content of that attribute, not the fully qualified
-          attribute.
-
-        * ``anchor`` is a pattern that matches the entire anchor, with
-          its contents.
-
-        If more than one link matches, then the ``index`` link is
-        followed.  If ``index`` is not given and more than one link
-        matches, or if no link matches, then ``IndexError`` will be
-        raised.
-
-        If you give ``verbose`` then messages will be printed about
-        each link, and why it does or doesn't match.  If you use
-        ``app.click(verbose=True)`` you'll see a list of all the
-        links.
-
-        You can use multiple criteria to essentially assert multiple
-        aspects about the link, e.g., where the link's destination is.
-        """
-        __tracebackhide__ = True
-        found_html, found_desc, found_attrs = self._find_element(
-            tag='a', href_attr='href',
-            href_extract=None,
-            content=description,
-            id=linkid, 
-            href_pattern=href,
-            html_pattern=anchor,
-            index=index, verbose=verbose)
-        return self.goto(found_attrs['uri'])
-
-    def clickbutton(self, description=None, buttonid=None, href=None,
-                    button=None, index=None, verbose=False):
-        """
-        Like ``.click()``, except looks for link-like buttons.
-        This kind of button should look like
-        ``<button onclick="...location.href='url'...">``.
-        """
-        __tracebackhide__ = True
-        found_html, found_desc, found_attrs = self._find_element(
-            tag='button', href_attr='onclick',
-            href_extract=re.compile(r"location\.href='(.*?)'"),
-            content=description,
-            id=buttonid,
-            href_pattern=href,
-            html_pattern=button,
-            index=index, verbose=verbose)
-        return self.goto(found_attrs['uri'])
-
-    def _find_element(self, tag, href_attr, href_extract,
-                      content, id,
-                      href_pattern,
-                      html_pattern,
-                      index, verbose):
-        content_pat = _make_pattern(content)
-        id_pat = _make_pattern(id)
-        href_pat = _make_pattern(href_pattern)
-        html_pat = _make_pattern(html_pattern)
-
-        _tag_re = re.compile(r'<%s\s+(.*?)>(.*?)</%s>' % (tag, tag),
-                             re.I+re.S)
-
-        def printlog(s):
-            if verbose:
-                print s
-
-        found_links = []
-        total_links = 0
-        for match in _tag_re.finditer(self.body):
-            el_html = match.group(0)
-            el_attr = match.group(1)
-            el_content = match.group(2)
-            attrs = _parse_attrs(el_attr)
-            if verbose:
-                printlog('Element: %r' % el_html)
-            if not attrs.get(href_attr):
-                printlog('  Skipped: no %s attribute' % href_attr)
-                continue
-            el_href = attrs[href_attr]
-            if href_extract:
-                m = href_extract.search(el_href)
-                if not m:
-                    printlog("  Skipped: doesn't match extract pattern")
-                    continue
-                el_href = m.group(1)
-            attrs['uri'] = el_href
-            if el_href.startswith('#'):
-                printlog('  Skipped: only internal fragment href')
-                continue
-            if el_href.startswith('javascript:'):
-                printlog('  Skipped: cannot follow javascript:')
-                continue
-            total_links += 1
-            if content_pat and not content_pat(el_content):
-                printlog("  Skipped: doesn't match description")
-                continue
-            if id_pat and not id_pat(attrs.get('id', '')):
-                printlog("  Skipped: doesn't match id")
-                continue
-            if href_pat and not href_pat(el_href):
-                printlog("  Skipped: doesn't match href")
-                continue
-            if html_pat and not html_pat(el_html):
-                printlog("  Skipped: doesn't match html")
-                continue
-            printlog("  Accepted")
-            found_links.append((el_html, el_content, attrs))
-        if not found_links:
-            raise IndexError(
-                "No matching elements found (from %s possible)"
-                % total_links)
-        if index is None:
-            if len(found_links) > 1:
-                raise IndexError(
-                    "Multiple links match: %s"
-                    % ', '.join([repr(anc) for anc, d, attr in found_links]))
-            found_link = found_links[0]
-        else:
-            try:
-                found_link = found_links[index]
-            except IndexError:
-                raise IndexError(
-                    "Only %s (out of %s) links match; index %s out of range"
-                    % (len(found_links), total_links, index))
-        return found_link
-
-    def goto(self, href, method='get', **args):
-        """
-        Go to the (potentially relative) link ``href``, using the
-        given method (``'get'`` or ``'post'``) and any extra arguments
-        you want to pass to the ``app.get()`` or ``app.post()``
-        methods.
-
-        All hostnames and schemes will be ignored.
-        """
-        scheme, host, path, query, fragment = urlparse.urlsplit(href)
-        # We
-        scheme = host = fragment = ''
-        href = urlparse.urlunsplit((scheme, host, path, query, fragment))
-        href = urlparse.urljoin(self.request.full_url, href)
-        method = method.lower()
-        assert method in ('get', 'post'), (
-            'Only "get" or "post" are allowed for method (you gave %r)'
-            % method)
-        if method == 'get':
-            method = self.test_app.get
-        else:
-            method = self.test_app.post
-        return method(href, **args)
-
-    _normal_body_regex = re.compile(r'[ \n\r\t]+')
-
-    def normal_body__get(self):
-        if self._normal_body is None:
-            self._normal_body = self._normal_body_regex.sub(
-                ' ', self.body)
-        return self._normal_body
-
-    normal_body = property(normal_body__get,
-                           doc="""
-                           Return the whitespace-normalized body
-                           """)
-
-    def __contains__(self, s):
-        """
-        A response 'contains' a string if it is present in the body
-        of the response.  Whitespace is normalized when searching
-        for a string.
-        """
-        if not isinstance(s, (str, unicode)):
-            s = str(s)
-        if isinstance(s, unicode):
-            ## FIXME: we don't know that this response uses utf8:
-            s = s.encode('utf8')
-        return (self.body.find(s) != -1
-                or self.normal_body.find(s) != -1)
-
-    def mustcontain(self, *strings, **kw):
-        """
-        Assert that the response contains all of the strings passed
-        in as arguments.
-
-        Equivalent to::
-
-            assert string in res
-        """
-        if 'no' in kw:
-            no = kw['no']
-            del kw['no']
-            if isinstance(no, basestring):
-                no = [no]
-        else:
-            no = []
-        if kw:
-            raise TypeError(
-                "The only keyword argument allowed is 'no'")
-        for s in strings:
-            if not s in self:
-                print >> sys.stderr, "Actual response (no %r):" % s
-                print >> sys.stderr, self
-                raise IndexError(
-                    "Body does not contain string %r" % s)
-        for no_s in no:
-            if no_s in self:
-                print >> sys.stderr, "Actual response (has %r)" % s
-                print >> sys.stderr, self
-                raise IndexError(
-                    "Body contains string %r" % s)
-
-    def __repr__(self):
-        return '<Response %s %r>' % (self.full_status, self.body[:20])
-
-    def __str__(self):
-        simple_body = '\n'.join([l for l in self.body.splitlines()
-                                 if l.strip()])
-        return 'Response: %s\n%s\n%s' % (
-            self.status,
-            '\n'.join(['%s: %s' % (n, v) for n, v in self.headers]),
-            simple_body)
-
-    def showbrowser(self):
-        """
-        Show this response in a browser window (for debugging purposes,
-        when it's hard to read the HTML).
-        """
-        import webbrowser
-        fn = tempnam_no_warning(None, 'paste-fixture') + '.html'
-        f = open(fn, 'wb')
-        f.write(self.body)
-        f.close()
-        url = 'file:' + fn.replace(os.sep, '/')
-        webbrowser.open_new(url)
-
-class TestRequest(object):
-
-    # for py.test
-    disabled = True
-
-    """
-    Instances of this class are created by `TestApp
-    <class-paste.fixture.TestApp.html>`_ with the ``.get()`` and
-    ``.post()`` methods, and are consumed there by ``.do_request()``.
-
-    Instances are also available as a ``.req`` attribute on
-    `TestResponse <class-paste.fixture.TestResponse.html>`_ instances.
-
-    Useful attributes:
-
-    ``url``:
-        The url (actually usually the path) of the request, without
-        query string.
-
-    ``environ``:
-        The environment dictionary used for the request.
-
-    ``full_url``:
-        The url/path, with query string.
-    """
-
-    def __init__(self, url, environ, expect_errors=False):
-        if url.startswith('http://localhost'):
-            url = url[len('http://localhost'):]
-        self.url = url
-        self.environ = environ
-        if environ.get('QUERY_STRING'):
-            self.full_url = url + '?' + environ['QUERY_STRING']
-        else:
-            self.full_url = url
-        self.expect_errors = expect_errors
-
-
-class Form(object):
-
-    """
-    This object represents a form that has been found in a page.
-    This has a couple useful attributes:
-
-    ``text``:
-        the full HTML of the form.
-
-    ``action``:
-        the relative URI of the action.
-
-    ``method``:
-        the method (e.g., ``'GET'``).
-
-    ``id``:
-        the id, or None if not given.
-
-    ``fields``:
-        a dictionary of fields, each value is a list of fields by
-        that name.  ``<input type=\"radio\">`` and ``<select>`` are
-        both represented as single fields with multiple options.
-    """
-
-    # @@: This really should be using Mechanize/ClientForm or
-    # something...
-
-    _tag_re = re.compile(r'<(/?)([:a-z0-9_\-]*)([^>]*?)>', re.I)
-
-    def __init__(self, response, text):
-        self.response = response
-        self.text = text
-        self._parse_fields()
-        self._parse_action()
-
-    def _parse_fields(self):
-        in_select = None
-        in_textarea = None
-        fields = {}
-        for match in self._tag_re.finditer(self.text):
-            end = match.group(1) == '/'
-            tag = match.group(2).lower()
-            if tag not in ('input', 'select', 'option', 'textarea',
-                           'button'):
-                continue
-            if tag == 'select' and end:
-                assert in_select, (
-                    '%r without starting select' % match.group(0))
-                in_select = None
-                continue
-            if tag == 'textarea' and end:
-                assert in_textarea, (
-                    "</textarea> with no <textarea> at %s" % match.start())
-                in_textarea[0].value = html_unquote(self.text[in_textarea[1]:match.start()])
-                in_textarea = None
-                continue
-            if end:
-                continue
-            attrs = _parse_attrs(match.group(3))
-            if 'name' in attrs:
-                name = attrs.pop('name')
-            else:
-                name = None
-            if tag == 'option':
-                in_select.options.append((attrs.get('value'),
-                                          'selected' in attrs))
-                continue
-            if tag == 'input' and attrs.get('type') == 'radio':
-                field = fields.get(name)
-                if not field:
-                    field = Radio(self, tag, name, match.start(), **attrs)
-                    fields.setdefault(name, []).append(field)
-                else:
-                    field = field[0]
-                    assert isinstance(field, Radio)
-                field.options.append((attrs.get('value'),
-                                      'checked' in attrs))
-                continue
-            tag_type = tag
-            if tag == 'input':
-                tag_type = attrs.get('type', 'text').lower()
-            FieldClass = Field.classes.get(tag_type, Field)
-            field = FieldClass(self, tag, name, match.start(), **attrs)
-            if tag == 'textarea':
-                assert not in_textarea, (
-                    "Nested textareas: %r and %r"
-                    % (in_textarea, match.group(0)))
-                in_textarea = field, match.end()
-            elif tag == 'select':
-                assert not in_select, (
-                    "Nested selects: %r and %r"
-                    % (in_select, match.group(0)))
-                in_select = field
-            fields.setdefault(name, []).append(field)
-        self.fields = fields
-
-    def _parse_action(self):
-        self.action = None
-        for match in self._tag_re.finditer(self.text):
-            end = match.group(1) == '/'
-            tag = match.group(2).lower()
-            if tag != 'form':
-                continue
-            if end:
-                break
-            attrs = _parse_attrs(match.group(3))
-            self.action = attrs.get('action', '')
-            self.method = attrs.get('method', 'GET')
-            self.id = attrs.get('id')
-            # @@: enctype?
-        else:
-            assert 0, "No </form> tag found"
-        assert self.action is not None, (
-            "No <form> tag found")
-
-    def __setitem__(self, name, value):
-        """
-        Set the value of the named field.  If there is 0 or multiple
-        fields by that name, it is an error.
-
-        Setting the value of a ``<select>`` selects the given option
-        (and confirms it is an option).  Setting radio fields does the
-        same.  Checkboxes get boolean values.  You cannot set hidden
-        fields or buttons.
-
-        Use ``.set()`` if there is any ambiguity and you must provide
-        an index.
-        """
-        fields = self.fields.get(name)
-        assert fields is not None, (
-            "No field by the name %r found (fields: %s)"
-            % (name, ', '.join(map(repr, self.fields.keys()))))
-        assert len(fields) == 1, (
-            "Multiple fields match %r: %s"
-            % (name, ', '.join(map(repr, fields))))
-        fields[0].value = value
-
-    def __getitem__(self, name):
-        """
-        Get the named field object (ambiguity is an error).
-        """
-        fields = self.fields.get(name)
-        assert fields is not None, (
-            "No field by the name %r found" % name)
-        assert len(fields) == 1, (
-            "Multiple fields match %r: %s"
-            % (name, ', '.join(map(repr, fields))))
-        return fields[0]
-
-    def set(self, name, value, index=None):
-        """
-        Set the given name, using ``index`` to disambiguate.
-        """
-        if index is None:
-            self[name] = value
-        else:
-            fields = self.fields.get(name)
-            assert fields is not None, (
-                "No fields found matching %r" % name)
-            field = fields[index]
-            field.value = value
-
-    def get(self, name, index=None, default=NoDefault):
-        """
-        Get the named/indexed field object, or ``default`` if no field
-        is found.
-        """
-        fields = self.fields.get(name)
-        if fields is None and default is not NoDefault:
-            return default
-        if index is None:
-            return self[name]
-        else:
-            fields = self.fields.get(name)
-            assert fields is not None, (
-                "No fields found matching %r" % name)
-            field = fields[index]
-            return field
-
-    def select(self, name, value, index=None):
-        """
-        Like ``.set()``, except also confirms the target is a
-        ``<select>``.
-        """
-        field = self.get(name, index=index)
-        assert isinstance(field, Select)
-        field.value = value
-
-    def submit(self, name=None, index=None, **args):
-        """
-        Submits the form.  If ``name`` is given, then also select that
-        button (using ``index`` to disambiguate)``.
-
-        Any extra keyword arguments are passed to the ``.get()`` or
-        ``.post()`` method.
-        """
-        fields = self.submit_fields(name, index=index)
-        return self.response.goto(self.action, method=self.method,
-                                  params=fields, **args)
-
-    def submit_fields(self, name=None, index=None):
-        """
-        Return a list of ``[(name, value), ...]`` for the current
-        state of the form.
-        """
-        submit = []
-        if name is not None:
-            field = self.get(name, index=index)
-            submit.append((field.name, field.value_if_submitted()))
-        for name, fields in self.fields.items():
-            if name is None:
-                continue
-            for field in fields:
-                value = field.value
-                if value is None:
-                    continue
-                submit.append((name, value))
-        return submit
-
-
-_attr_re = re.compile(r'([^= \n\r\t]+)[ \n\r\t]*(?:=[ \n\r\t]*(?:"([^"]*)"|([^"][^ \n\r\t>]*)))?', re.S)
-
-def _parse_attrs(text):
-    attrs = {}
-    for match in _attr_re.finditer(text):
-        attr_name = match.group(1).lower()
-        attr_body = match.group(2) or match.group(3)
-        attr_body = html_unquote(attr_body or '')
-        attrs[attr_name] = attr_body
-    return attrs
-
-class Field(object):
-
-    """
-    Field object.
-    """
-
-    # Dictionary of field types (select, radio, etc) to classes
-    classes = {}
-
-    settable = True
-
-    def __init__(self, form, tag, name, pos,
-                 value=None, id=None, **attrs):
-        self.form = form
-        self.tag = tag
-        self.name = name
-        self.pos = pos
-        self._value = value
-        self.id = id
-        self.attrs = attrs
-
-    def value__set(self, value):
-        if not self.settable:
-            raise AttributeError(
-                "You cannot set the value of the <%s> field %r"
-                % (self.tag, self.name))
-        self._value = value
-
-    def force_value(self, value):
-        """
-        Like setting a value, except forces it even for, say, hidden
-        fields.
-        """
-        self._value = value
-
-    def value__get(self):
-        return self._value
-
-    value = property(value__get, value__set)
-
-class Select(Field):
-
-    """
-    Field representing ``<select>``
-    """
-
-    def __init__(self, *args, **attrs):
-        super(Select, self).__init__(*args, **attrs)
-        self.options = []
-        self.multiple = attrs.get('multiple')
-        assert not self.multiple, (
-            "<select multiple> not yet supported")
-        # Undetermined yet:
-        self.selectedIndex = None
-
-    def value__set(self, value):
-        for i, (option, checked) in enumerate(self.options):
-            if option == str(value):
-                self.selectedIndex = i
-                break
-        else:
-            raise ValueError(
-                "Option %r not found (from %s)"
-                % (value, ', '.join(
-                [repr(o) for o, c in self.options])))
-
-    def value__get(self):
-        if self.selectedIndex is not None:
-            return self.options[self.selectedIndex][0]
-        else:
-            for option, checked in self.options:
-                if checked:
-                    return option
-            else:
-                if self.options:
-                    return self.options[0][0]
-                else:
-                    return None
-
-    value = property(value__get, value__set)
-
-Field.classes['select'] = Select
-
-class Radio(Select):
-
-    """
-    Field representing ``<input type="radio">``
-    """
-
-Field.classes['radio'] = Radio
-
-class Checkbox(Field):
-
-    """
-    Field representing ``<input type="checkbox">``
-    """
-
-    def __init__(self, *args, **attrs):
-        super(Checkbox, self).__init__(*args, **attrs)
-        self.checked = 'checked' in attrs
-
-    def value__set(self, value):
-        self.checked = not not value
-
-    def value__get(self):
-        if self.checked:
-            if self._value is None:
-                return 'on'
-            else:
-                return self._value
-        else:
-            return None
-
-    value = property(value__get, value__set)
-
-Field.classes['checkbox'] = Checkbox
-
-class Text(Field):
-    """
-    Field representing ``<input type="text">``
-    """
-    def __init__(self, form, tag, name, pos,
-                 value='', id=None, **attrs):
-        #text fields default to empty string        
-        Field.__init__(self, form, tag, name, pos,
-                       value=value, id=id, **attrs)
-                        
-Field.classes['text'] = Text
-
-class Textarea(Text):
-    """
-    Field representing ``<textarea>``
-    """
-
-Field.classes['textarea'] = Textarea
-
-class Hidden(Text):
-    """
-    Field representing ``<input type="hidden">``
-    """
-
-Field.classes['hidden'] = Hidden
-
-class Submit(Field):
-    """
-    Field representing ``<input type="submit">`` and ``<button>``
-    """
-    
-    settable = False
-
-    def value__get(self):
-        return None
-
-    value = property(value__get)
-
-    def value_if_submitted(self):
-        return self._value
-
-Field.classes['submit'] = Submit
-
-Field.classes['button'] = Submit
-
-Field.classes['image'] = Submit
-
-############################################################
-## Command-line testing
-############################################################
-
-
-class TestFileEnvironment(object):
-
-    """
-    This represents an environment in which files will be written, and
-    scripts will be run.
-    """
-
-    # for py.test
-    disabled = True
-
-    def __init__(self, base_path, template_path=None,
-                 script_path=None,
-                 environ=None, cwd=None, start_clear=True,
-                 ignore_paths=None, ignore_hidden=True):
-        """
-        Creates an environment.  ``base_path`` is used as the current
-        working directory, and generally where changes are looked for.
-
-        ``template_path`` is the directory to look for *template*
-        files, which are files you'll explicitly add to the
-        environment.  This is done with ``.writefile()``.
-
-        ``script_path`` is the PATH for finding executables.  Usually
-        grabbed from ``$PATH``.
-
-        ``environ`` is the operating system environment,
-        ``os.environ`` if not given.
-
-        ``cwd`` is the working directory, ``base_path`` by default.
-
-        If ``start_clear`` is true (default) then the ``base_path``
-        will be cleared (all files deleted) when an instance is
-        created.  You can also use ``.clear()`` to clear the files.
-
-        ``ignore_paths`` is a set of specific filenames that should be
-        ignored when created in the environment.  ``ignore_hidden``
-        means, if true (default) that filenames and directories
-        starting with ``'.'`` will be ignored.
-        """
-        self.base_path = base_path
-        self.template_path = template_path
-        if environ is None:
-            environ = os.environ.copy()
-        self.environ = environ
-        if script_path is None:
-            if sys.platform == 'win32':
-                script_path = environ.get('PATH', '').split(';')
-            else:       
-                script_path = environ.get('PATH', '').split(':')
-        self.script_path = script_path
-        if cwd is None:
-            cwd = base_path
-        self.cwd = cwd
-        if start_clear:
-            self.clear()
-        elif not os.path.exists(base_path):
-            os.makedirs(base_path)
-        self.ignore_paths = ignore_paths or []
-        self.ignore_hidden = ignore_hidden
-
-    def run(self, script, *args, **kw):
-        """
-        Run the command, with the given arguments.  The ``script``
-        argument can have space-separated arguments, or you can use
-        the positional arguments.
-
-        Keywords allowed are:
-
-        ``expect_error``: (default False)
-            Don't raise an exception in case of errors
-        ``expect_stderr``: (default ``expect_error``)
-            Don't raise an exception if anything is printed to stderr
-        ``stdin``: (default ``""``)
-            Input to the script
-        ``printresult``: (default True)
-            Print the result after running
-        ``cwd``: (default ``self.cwd``)
-            The working directory to run in
-
-        Returns a `ProcResponse
-        <class-paste.fixture.ProcResponse.html>`_ object.
-        """
-        __tracebackhide__ = True
-        expect_error = _popget(kw, 'expect_error', False)
-        expect_stderr = _popget(kw, 'expect_stderr', expect_error)
-        cwd = _popget(kw, 'cwd', self.cwd)
-        stdin = _popget(kw, 'stdin', None)
-        printresult = _popget(kw, 'printresult', True)
-        args = map(str, args)
-        assert not kw, (
-            "Arguments not expected: %s" % ', '.join(kw.keys()))
-        if ' ' in script:
-            assert not args, (
-                "You cannot give a multi-argument script (%r) "
-                "and arguments (%s)" % (script, args))
-            script, args = script.split(None, 1)
-            args = shlex.split(args)
-        script = self._find_exe(script)
-        all = [script] + args
-        files_before = self._find_files()
-        proc = subprocess.Popen(all, stdin=subprocess.PIPE,
-                                stderr=subprocess.PIPE,
-                                stdout=subprocess.PIPE,
-                                cwd=cwd,
-                                env=self.environ)
-        stdout, stderr = proc.communicate(stdin)
-        files_after = self._find_files()
-        result = ProcResult(
-            self, all, stdin, stdout, stderr,
-            returncode=proc.returncode,
-            files_before=files_before,
-            files_after=files_after)
-        if printresult:
-            print result
-            print '-'*40
-        if not expect_error:
-            result.assert_no_error()
-        if not expect_stderr:
-            result.assert_no_stderr()
-        return result
-
-    def _find_exe(self, script_name):
-        if self.script_path is None:
-            script_name = os.path.join(self.cwd, script_name)
-            if not os.path.exists(script_name):
-                raise OSError(
-                    "Script %s does not exist" % script_name)
-            return script_name
-        for path in self.script_path:
-            fn = os.path.join(path, script_name)
-            if os.path.exists(fn):
-                return fn
-        raise OSError(
-            "Script %s could not be found in %s"
-            % (script_name, ':'.join(self.script_path)))
-
-    def _find_files(self):
-        result = {}
-        for fn in os.listdir(self.base_path):
-            if self._ignore_file(fn):
-                continue
-            self._find_traverse(fn, result)
-        return result
-
-    def _ignore_file(self, fn):
-        if fn in self.ignore_paths:
-            return True
-        if self.ignore_hidden and os.path.basename(fn).startswith('.'):
-            return True
-        return False
-
-    def _find_traverse(self, path, result):
-        full = os.path.join(self.base_path, path)
-        if os.path.isdir(full):
-            result[path] = FoundDir(self.base_path, path)
-            for fn in os.listdir(full):
-                fn = os.path.join(path, fn)
-                if self._ignore_file(fn):
-                    continue
-                self._find_traverse(fn, result)
-        else:
-            result[path] = FoundFile(self.base_path, path)
-
-    def clear(self):
-        """
-        Delete all the files in the base directory.
-        """
-        if os.path.exists(self.base_path):
-            shutil.rmtree(self.base_path)
-        os.mkdir(self.base_path)
-
-    def writefile(self, path, content=None,
-                  frompath=None):
-        """
-        Write a file to the given path.  If ``content`` is given then
-        that text is written, otherwise the file in ``frompath`` is
-        used.  ``frompath`` is relative to ``self.template_path``
-        """
-        full = os.path.join(self.base_path, path)
-        if not os.path.exists(os.path.dirname(full)):
-            os.makedirs(os.path.dirname(full))
-        f = open(full, 'wb')
-        if content is not None:
-            f.write(content)
-        if frompath is not None:
-            if self.template_path:
-                frompath = os.path.join(self.template_path, frompath)
-            f2 = open(frompath, 'rb')
-            f.write(f2.read())
-            f2.close()
-        f.close()
-        return FoundFile(self.base_path, path)
-
-class ProcResult(object):
-
-    """
-    Represents the results of running a command in
-    `TestFileEnvironment
-    <class-paste.fixture.TestFileEnvironment.html>`_.
-
-    Attributes to pay particular attention to:
-
-    ``stdout``, ``stderr``:
-        What is produced
-
-    ``files_created``, ``files_deleted``, ``files_updated``:
-        Dictionaries mapping filenames (relative to the ``base_dir``)
-        to `FoundFile <class-paste.fixture.FoundFile.html>`_ or
-        `FoundDir <class-paste.fixture.FoundDir.html>`_ objects.
-    """
-
-    def __init__(self, test_env, args, stdin, stdout, stderr,
-                 returncode, files_before, files_after):
-        self.test_env = test_env
-        self.args = args
-        self.stdin = stdin
-        self.stdout = stdout
-        self.stderr = stderr
-        self.returncode = returncode
-        self.files_before = files_before
-        self.files_after = files_after
-        self.files_deleted = {}
-        self.files_updated = {}
-        self.files_created = files_after.copy()
-        for path, f in files_before.items():
-            if path not in files_after:
-                self.files_deleted[path] = f
-                continue
-            del self.files_created[path]
-            if f.mtime < files_after[path].mtime:
-                self.files_updated[path] = files_after[path]
-
-    def assert_no_error(self):
-        __tracebackhide__ = True
-        assert self.returncode == 0, (
-            "Script returned code: %s" % self.returncode)
-
-    def assert_no_stderr(self):
-        __tracebackhide__ = True
-        if self.stderr:
-            print 'Error output:'
-            print self.stderr
-            raise AssertionError("stderr output not expected")
-
-    def __str__(self):
-        s = ['Script result: %s' % ' '.join(self.args)]
-        if self.returncode:
-            s.append('  return code: %s' % self.returncode)
-        if self.stderr:
-            s.append('-- stderr: --------------------')
-            s.append(self.stderr)
-        if self.stdout:
-            s.append('-- stdout: --------------------')
-            s.append(self.stdout)
-        for name, files, show_size in [
-            ('created', self.files_created, True),
-            ('deleted', self.files_deleted, True),
-            ('updated', self.files_updated, True)]:
-            if files:
-                s.append('-- %s: -------------------' % name)
-                files = files.items()
-                files.sort()
-                last = ''
-                for path, f in files:
-                    t = '  %s' % _space_prefix(last, path, indent=4,
-                                               include_sep=False)
-                    last = path
-                    if show_size and f.size != 'N/A':
-                        t += '  (%s bytes)' % f.size
-                    s.append(t)
-        return '\n'.join(s)
-
-class FoundFile(object):
-
-    """
-    Represents a single file found as the result of a command.
-
-    Has attributes:
-
-    ``path``:
-        The path of the file, relative to the ``base_path``
-
-    ``full``:
-        The full path
-
-    ``stat``:
-        The results of ``os.stat``.  Also ``mtime`` and ``size``
-        contain the ``.st_mtime`` and ``st_size`` of the stat.
-
-    ``bytes``:
-        The contents of the file.
-
-    You may use the ``in`` operator with these objects (tested against
-    the contents of the file), and the ``.mustcontain()`` method.
-    """
-
-    file = True
-    dir = False
-
-    def __init__(self, base_path, path):
-        self.base_path = base_path
-        self.path = path
-        self.full = os.path.join(base_path, path)
-        self.stat = os.stat(self.full)
-        self.mtime = self.stat.st_mtime
-        self.size = self.stat.st_size
-        self._bytes = None
-
-    def bytes__get(self):
-        if self._bytes is None:
-            f = open(self.full, 'rb')
-            self._bytes = f.read()
-            f.close()
-        return self._bytes
-    bytes = property(bytes__get)
-
-    def __contains__(self, s):
-        return s in self.bytes
-
-    def mustcontain(self, s):
-        __tracebackhide__ = True
-        bytes = self.bytes
-        if s not in bytes:
-            print 'Could not find %r in:' % s
-            print bytes
-            assert s in bytes
-
-    def __repr__(self):
-        return '<%s %s:%s>' % (
-            self.__class__.__name__,
-            self.base_path, self.path)
-
-class FoundDir(object):
-
-    """
-    Represents a directory created by a command.
-    """
-
-    file = False
-    dir = True
-
-    def __init__(self, base_path, path):
-        self.base_path = base_path
-        self.path = path
-        self.full = os.path.join(base_path, path)
-        self.size = 'N/A'
-        self.mtime = 'N/A'
-
-    def __repr__(self):
-        return '<%s %s:%s>' % (
-            self.__class__.__name__,
-            self.base_path, self.path)
-
-def _popget(d, key, default=None):
-    """
-    Pop the key if found (else return default)
-    """
-    if key in d:
-        return d.pop(key)
-    return default
-
-def _space_prefix(pref, full, sep=None, indent=None, include_sep=True):
-    """
-    Anything shared by pref and full will be replaced with spaces
-    in full, and full returned.
-    """
-    if sep is None:
-        sep = os.path.sep
-    pref = pref.split(sep)
-    full = full.split(sep)
-    padding = []
-    while pref and full and pref[0] == full[0]:
-        if indent is None:
-            padding.append(' ' * (len(full[0]) + len(sep)))
-        else:
-            padding.append(' ' * indent)
-        full.pop(0)
-        pref.pop(0)
-    if padding:
-        if include_sep:
-            return ''.join(padding) + sep + sep.join(full)
-        else:
-            return ''.join(padding) + sep.join(full)
-    else:
-        return sep.join(full)
-
-def _make_pattern(pat):
-    if pat is None:
-        return None
-    if isinstance(pat, (str, unicode)):
-        pat = re.compile(pat)
-    if hasattr(pat, 'search'):
-        return pat.search
-    if callable(pat):
-        return pat
-    assert 0, (
-        "Cannot make callable pattern object out of %r" % pat)
-
-def setup_module(module=None):
-    """
-    This is used by py.test if it is in the module, so you can
-    import this directly.
-
-    Use like::
-
-        from paste.fixture import setup_module
-    """
-    # Deprecated June 2008
-    import warnings
-    warnings.warn(
-        'setup_module is deprecated',
-        DeprecationWarning, 2)
-    if module is None:
-        # The module we were called from must be the module...
-        module = sys._getframe().f_back.f_globals['__name__']
-    if isinstance(module, (str, unicode)):
-        module = sys.modules[module]
-    if hasattr(module, 'reset_state'):
-        module.reset_state()
-
-def html_unquote(v):
-    """
-    Unquote (some) entities in HTML.  (incomplete)
-    """
-    for ent, repl in [('&nbsp;', ' '), ('&gt;', '>'),
-                      ('&lt;', '<'), ('&quot;', '"'),
-                      ('&amp;', '&')]:
-        v = v.replace(ent, repl)
-    return v
diff --git a/lib/paste/flup_session.py b/lib/paste/flup_session.py
@@ -1,108 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-"""
-Creates a session object.
-
-In your application, use::
-
-    environ['paste.flup_session_service'].session
-
-This will return a dictionary.  The contents of this dictionary will
-be saved to disk when the request is completed.  The session will be
-created when you first fetch the session dictionary, and a cookie will
-be sent in that case.  There's current no way to use sessions without
-cookies, and there's no way to delete a session except to clear its
-data.
-"""
-
-from paste import httpexceptions
-from paste import wsgilib
-import flup.middleware.session
-flup_session = flup.middleware.session
-
-# This is a dictionary of existing stores, keyed by a tuple of
-# store type and parameters
-store_cache = {}
-
-class NoDefault(object):
-    pass
-
-class SessionMiddleware(object):
-
-    session_classes = {
-        'memory': (flup_session.MemorySessionStore,
-                   [('session_timeout', 'timeout', int, 60)]),
-        'disk': (flup_session.DiskSessionStore,
-                 [('session_timeout', 'timeout', int, 60),
-                  ('session_dir', 'storeDir', str, '/tmp/sessions')]),
-        'shelve': (flup_session.ShelveSessionStore,
-                   [('session_timeout', 'timeout', int, 60),
-                    ('session_file', 'storeFile', str,
-                     '/tmp/session.shelve')]),
-        }
-
-
-    def __init__(self, app,
-                 global_conf=None,
-                 session_type=NoDefault,
-                 cookie_name=NoDefault,
-                 **store_config
-                 ):
-        self.application = app
-        if session_type is NoDefault:
-            session_type = global_conf.get('session_type', 'disk')
-        self.session_type = session_type
-        try:
-            self.store_class, self.store_args = self.session_classes[self.session_type]
-        except KeyError:
-            raise KeyError(
-                "The session_type %s is unknown (I know about %s)"
-                % (self.session_type,
-                   ', '.join(self.session_classes.keys())))
-        kw = {}
-        for config_name, kw_name, coercer, default in self.store_args:
-            value = coercer(store_config.get(config_name, default))
-            kw[kw_name] = value
-        self.store = self.store_class(**kw)
-        if cookie_name is NoDefault:
-            cookie_name = global_conf.get('session_cookie', '_SID_')
-        self.cookie_name = cookie_name
-        
-    def __call__(self, environ, start_response):
-        service = flup_session.SessionService(
-            self.store, environ, cookieName=self.cookie_name,
-            fieldName=self.cookie_name)
-        environ['paste.flup_session_service'] = service
-
-        def cookie_start_response(status, headers, exc_info=None):
-            service.addCookie(headers)
-            return start_response(status, headers, exc_info)
-
-        try:
-            app_iter = self.application(environ, cookie_start_response)
-        except httpexceptions.HTTPException, e:
-            headers = (e.headers or {}).items()
-            service.addCookie(headers)
-            e.headers = dict(headers)
-            service.close()
-            raise
-        except:
-            service.close()
-            raise
-
-        return wsgilib.add_close(app_iter, service.close)
-            
-def make_session_middleware(app, global_conf,
-                            session_type=NoDefault,
-                            cookie_name=NoDefault,
-                            **store_config):
-    """
-    Wraps the application in a session-managing middleware.
-    The session service can then be found in
-    ``environ['paste.flup_session_service']``
-    """
-    return SessionMiddleware(
-        app, global_conf=global_conf,
-        session_type=session_type, cookie_name=cookie_name,
-        **store_config)
diff --git a/lib/paste/gzipper.py b/lib/paste/gzipper.py
@@ -1,111 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-"""
-WSGI middleware
-
-Gzip-encodes the response.
-"""
-
-import gzip
-from paste.response import header_value, remove_header
-from paste.httpheaders import CONTENT_LENGTH
-
-try:
-    from cStringIO import StringIO
-except ImportError:
-    from StringIO import StringIO
-
-class GzipOutput(object):
-    pass
-
-class middleware(object):
-
-    def __init__(self, application, compress_level=6):
-        self.application = application
-        self.compress_level = int(compress_level)
-
-    def __call__(self, environ, start_response):
-        if 'gzip' not in environ.get('HTTP_ACCEPT_ENCODING', ''):
-            # nothing for us to do, so this middleware will
-            # be a no-op:
-            return self.application(environ, start_response)
-        response = GzipResponse(start_response, self.compress_level)
-        app_iter = self.application(environ,
-                                    response.gzip_start_response)
-        if app_iter:
-            response.finish_response(app_iter)
-
-        return response.write()
-
-class GzipResponse(object):
-
-    def __init__(self, start_response, compress_level):
-        self.start_response = start_response
-        self.compress_level = compress_level
-        self.buffer = StringIO()
-        self.compressible = False
-        self.content_length = None
-
-    def gzip_start_response(self, status, headers, exc_info=None):
-        self.headers = headers
-        ct = header_value(headers,'content-type')
-        ce = header_value(headers,'content-encoding')
-        self.compressible = False
-        if ct and (ct.startswith('text/') or ct.startswith('application/')) \
-            and 'zip' not in ct:
-            self.compressible = True
-        if ce:
-            self.compressible = False
-        if self.compressible:
-            headers.append(('content-encoding', 'gzip'))
-        remove_header(headers, 'content-length')
-        self.headers = headers
-        self.status = status
-        return self.buffer.write
-
-    def write(self):
-        out = self.buffer
-        out.seek(0)
-        s = out.getvalue()
-        out.close()
-        return [s]
-
-    def finish_response(self, app_iter):
-        if self.compressible:
-            output = gzip.GzipFile(mode='wb', compresslevel=self.compress_level,
-                fileobj=self.buffer)
-        else:
-            output = self.buffer
-        try:
-            for s in app_iter:
-                output.write(s)
-            if self.compressible:
-                output.close()
-        finally:
-            if hasattr(app_iter, 'close'):
-                app_iter.close()
-        content_length = self.buffer.tell()
-        CONTENT_LENGTH.update(self.headers, content_length)
-        self.start_response(self.status, self.headers)
-
-def filter_factory(application, **conf):
-    import warnings
-    warnings.warn(
-        'This function is deprecated; use make_gzip_middleware instead',
-        DeprecationWarning, 2)
-    def filter(application):
-        return middleware(application)
-    return filter
-
-def make_gzip_middleware(app, global_conf, compress_level=6):
-    """
-    Wrap the middleware, so that it applies gzipping to a response
-    when it is supported by the browser and the content is of
-    type ``text/*`` or ``application/*``
-    """
-    compress_level = int(compress_level)
-    return middleware(app, compress_level=compress_level)
diff --git a/lib/paste/httpexceptions.py b/lib/paste/httpexceptions.py
@@ -1,664 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-# (c) 2005 Ian Bicking, Clark C. Evans and contributors
-# This module is part of the Python Paste Project and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-# Some of this code was funded by http://prometheusresearch.com
-"""
-HTTP Exception Middleware
-
-This module processes Python exceptions that relate to HTTP exceptions
-by defining a set of exceptions, all subclasses of HTTPException, and a
-request handler (`middleware`) that catches these exceptions and turns
-them into proper responses.
-
-This module defines exceptions according to RFC 2068 [1]_ : codes with
-100-300 are not really errors; 400's are client errors, and 500's are
-server errors.  According to the WSGI specification [2]_ , the application
-can call ``start_response`` more then once only under two conditions:
-(a) the response has not yet been sent, or (b) if the second and
-subsequent invocations of ``start_response`` have a valid ``exc_info``
-argument obtained from ``sys.exc_info()``.  The WSGI specification then
-requires the server or gateway to handle the case where content has been
-sent and then an exception was encountered.
-
-Exceptions in the 5xx range and those raised after ``start_response``
-has been called are treated as serious errors and the ``exc_info`` is
-filled-in with information needed for a lower level module to generate a
-stack trace and log information.
-
-Exception
-  HTTPException
-    HTTPRedirection
-      * 300 - HTTPMultipleChoices
-      * 301 - HTTPMovedPermanently
-      * 302 - HTTPFound
-      * 303 - HTTPSeeOther
-      * 304 - HTTPNotModified
-      * 305 - HTTPUseProxy
-      * 306 - Unused (not implemented, obviously)
-      * 307 - HTTPTemporaryRedirect
-    HTTPError
-      HTTPClientError
-        * 400 - HTTPBadRequest
-        * 401 - HTTPUnauthorized
-        * 402 - HTTPPaymentRequired
-        * 403 - HTTPForbidden
-        * 404 - HTTPNotFound
-        * 405 - HTTPMethodNotAllowed
-        * 406 - HTTPNotAcceptable
-        * 407 - HTTPProxyAuthenticationRequired
-        * 408 - HTTPRequestTimeout
-        * 409 - HTTPConfict
-        * 410 - HTTPGone
-        * 411 - HTTPLengthRequired
-        * 412 - HTTPPreconditionFailed
-        * 413 - HTTPRequestEntityTooLarge
-        * 414 - HTTPRequestURITooLong
-        * 415 - HTTPUnsupportedMediaType
-        * 416 - HTTPRequestRangeNotSatisfiable
-        * 417 - HTTPExpectationFailed
-      HTTPServerError
-        * 500 - HTTPInternalServerError
-        * 501 - HTTPNotImplemented
-        * 502 - HTTPBadGateway
-        * 503 - HTTPServiceUnavailable
-        * 504 - HTTPGatewayTimeout
-        * 505 - HTTPVersionNotSupported
-
-References:
-
-.. [1] http://www.python.org/peps/pep-0333.html#error-handling
-.. [2] http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5
-
-"""
-
-import types
-from paste.wsgilib import catch_errors_app
-from paste.response import has_header, header_value, replace_header
-from paste.request import resolve_relative_url
-from paste.util.quoting import strip_html, html_quote, no_quote
-
-SERVER_NAME = 'WSGI Server'
-TEMPLATE = """\
-<html>\r
-  <head><title>%(title)s</title></head>\r
-  <body>\r
-    <h1>%(title)s</h1>\r
-    <p>%(body)s</p>\r
-    <hr noshade>\r
-    <div align="right">%(server)s</div>\r
-  </body>\r
-</html>\r
-"""
-
-class HTTPException(Exception):
-    """
-    the HTTP exception base class
-
-    This encapsulates an HTTP response that interrupts normal application
-    flow; but one which is not necessarly an error condition. For
-    example, codes in the 300's are exceptions in that they interrupt
-    normal processing; however, they are not considered errors.
-
-    This class is complicated by 4 factors:
-
-      1. The content given to the exception may either be plain-text or
-         as html-text.
-
-      2. The template may want to have string-substitutions taken from
-         the current ``environ`` or values from incoming headers. This
-         is especially troublesome due to case sensitivity.
-
-      3. The final output may either be text/plain or text/html
-         mime-type as requested by the client application.
-
-      4. Each exception has a default explanation, but those who
-         raise exceptions may want to provide additional detail.
-
-    Attributes:
-
-       ``code``
-           the HTTP status code for the exception
-
-       ``title``
-           remainder of the status line (stuff after the code)
-
-       ``explanation``
-           a plain-text explanation of the error message that is
-           not subject to environment or header substitutions;
-           it is accessible in the template via %(explanation)s
-
-       ``detail``
-           a plain-text message customization that is not subject
-           to environment or header substitutions; accessible in
-           the template via %(detail)s
-
-       ``template``
-           a content fragment (in HTML) used for environment and
-           header substitution; the default template includes both
-           the explanation and further detail provided in the
-           message
-
-       ``required_headers``
-           a sequence of headers which are required for proper
-           construction of the exception
-
-    Parameters:
-
-       ``detail``
-         a plain-text override of the default ``detail``
-
-       ``headers``
-         a list of (k,v) header pairs
-
-       ``comment``
-         a plain-text additional information which is
-         usually stripped/hidden for end-users
-
-    To override the template (which is HTML content) or the plain-text
-    explanation, one must subclass the given exception; or customize it
-    after it has been created.  This particular breakdown of a message
-    into explanation, detail and template allows both the creation of
-    plain-text and html messages for various clients as well as
-    error-free substitution of environment variables and headers.
-    """
-
-    code = None
-    title = None
-    explanation = ''
-    detail = ''
-    comment = ''
-    template = "%(explanation)s\r\n<br/>%(detail)s\r\n<!-- %(comment)s -->"
-    required_headers = ()
-
-    def __init__(self, detail=None, headers=None, comment=None):
-        assert self.code, "Do not directly instantiate abstract exceptions."
-        assert isinstance(headers, (type(None), list)), (
-            "headers must be None or a list: %r"
-            % headers)
-        assert isinstance(detail, (type(None), basestring)), (
-            "detail must be None or a string: %r" % detail)
-        assert isinstance(comment, (type(None), basestring)), (
-            "comment must be None or a string: %r" % comment)
-        self.headers = headers or tuple()
-        for req in self.required_headers:
-            assert headers and has_header(headers, req), (
-                "Exception %s must be passed the header %r "
-                "(got headers: %r)"
-                % (self.__class__.__name__, req, headers))
-        if detail is not None:
-            self.detail = detail
-        if comment is not None:
-            self.comment = comment
-        Exception.__init__(self,"%s %s\n%s\n%s\n" % (
-            self.code, self.title, self.explanation, self.detail))
-
-    def make_body(self, environ, template, escfunc, comment_escfunc=None):
-        comment_escfunc = comment_escfunc or escfunc
-        args = {'explanation': escfunc(self.explanation),
-                'detail': escfunc(self.detail),
-                'comment': comment_escfunc(self.comment)}
-        if HTTPException.template == self.template:
-            return template % args
-        for (k, v) in environ.items():
-            args[k] = escfunc(v)
-        if self.headers:
-            for (k, v) in self.headers:
-                args[k.lower()] = escfunc(v)
-        return template % args
-
-    def plain(self, environ):
-        """ text/plain representation of the exception """
-        body = self.make_body(environ, strip_html(self.template), no_quote)
-        return ('%s %s\r\n%s\r\n' % (self.code, self.title, body))
-
-    def html(self, environ):
-        """ text/html representation of the exception """
-        body = self.make_body(environ, self.template, html_quote, no_quote)
-        return TEMPLATE % {
-                   'title': self.title,
-                   'code': self.code,
-                   'server': SERVER_NAME,
-                   'body': body }
-
-    def prepare_content(self, environ):
-        if self.headers:
-            headers = list(self.headers)
-        else:
-            headers = []
-        if 'html' in environ.get('HTTP_ACCEPT','') or \
-            '*/*' in environ.get('HTTP_ACCEPT',''):
-            replace_header(headers, 'content-type', 'text/html')
-            content = self.html(environ)
-        else:
-            replace_header(headers, 'content-type', 'text/plain')
-            content = self.plain(environ)
-        if isinstance(content, unicode):
-            content = content.encode('utf8')
-            cur_content_type = (
-                header_value(headers, 'content-type')
-                or 'text/html')
-            replace_header(
-                headers, 'content-type',
-                cur_content_type + '; charset=utf8')
-        return headers, content
-
-    def response(self, environ):
-        from paste.wsgiwrappers import WSGIResponse
-        headers, content = self.prepare_content(environ)
-        resp = WSGIResponse(code=self.code, content=content)
-        resp.headers = resp.headers.fromlist(headers)
-        return resp
-
-    def wsgi_application(self, environ, start_response, exc_info=None):
-        """
-        This exception as a WSGI application
-        """
-        headers, content = self.prepare_content(environ)
-        start_response('%s %s' % (self.code, self.title),
-                       headers,
-                       exc_info)
-        return [content]
-
-    __call__ = wsgi_application
-
-    def __repr__(self):
-        return '<%s %s; code=%s>' % (self.__class__.__name__,
-                                     self.title, self.code)
-
-class HTTPError(HTTPException):
-    """
-    base class for status codes in the 400's and 500's
-
-    This is an exception which indicates that an error has occurred,
-    and that any work in progress should not be committed.  These are
-    typically results in the 400's and 500's.
-    """
-
-#
-# 3xx Redirection
-#
-#  This class of status code indicates that further action needs to be
-#  taken by the user agent in order to fulfill the request. The action
-#  required MAY be carried out by the user agent without interaction with
-#  the user if and only if the method used in the second request is GET or
-#  HEAD. A client SHOULD detect infinite redirection loops, since such
-#  loops generate network traffic for each redirection.
-#
-
-class HTTPRedirection(HTTPException):
-    """
-    base class for 300's status code (redirections)
-
-    This is an abstract base class for 3xx redirection.  It indicates
-    that further action needs to be taken by the user agent in order
-    to fulfill the request.  It does not necessarly signal an error
-    condition.
-    """
-
-class _HTTPMove(HTTPRedirection):
-    """
-    redirections which require a Location field
-
-    Since a 'Location' header is a required attribute of 301, 302, 303,
-    305 and 307 (but not 304), this base class provides the mechanics to
-    make this easy.  While this has the same parameters as HTTPException,
-    if a location is not provided in the headers; it is assumed that the
-    detail _is_ the location (this for backward compatibility, otherwise
-    we'd add a new attribute).
-    """
-    required_headers = ('location',)
-    explanation = 'The resource has been moved to'
-    template = (
-        '%(explanation)s <a href="%(location)s">%(location)s</a>;\r\n'
-        'you should be redirected automatically.\r\n'
-        '%(detail)s\r\n<!-- %(comment)s -->')
-
-    def __init__(self, detail=None, headers=None, comment=None):
-        assert isinstance(headers, (type(None), list))
-        headers = headers or []
-        location = header_value(headers,'location')
-        if not location:
-            location = detail
-            detail = ''
-            headers.append(('location', location))
-        assert location, ("HTTPRedirection specified neither a "
-                          "location in the headers nor did it "
-                          "provide a detail argument.")
-        HTTPRedirection.__init__(self, location, headers, comment)
-        if detail is not None:
-            self.detail = detail
-
-    def relative_redirect(cls, dest_uri, environ, detail=None, headers=None, comment=None):
-        """
-        Create a redirect object with the dest_uri, which may be relative, 
-        considering it relative to the uri implied by the given environ.
-        """
-        location = resolve_relative_url(dest_uri, environ)
-        headers = headers or []
-        headers.append(('Location', location))
-        return cls(detail=detail, headers=headers, comment=comment)
-    
-    relative_redirect = classmethod(relative_redirect)
-
-    def location(self):
-        for name, value in self.headers:
-            if name.lower() == 'location':
-                return value
-        else:
-            raise KeyError("No location set for %s" % self)
-
-class HTTPMultipleChoices(_HTTPMove):
-    code = 300
-    title = 'Multiple Choices'
-
-class HTTPMovedPermanently(_HTTPMove):
-    code = 301
-    title = 'Moved Permanently'
-
-class HTTPFound(_HTTPMove):
-    code = 302
-    title = 'Found'
-    explanation = 'The resource was found at'
-
-# This one is safe after a POST (the redirected location will be
-# retrieved with GET):
-class HTTPSeeOther(_HTTPMove):
-    code = 303
-    title = 'See Other'
-
-class HTTPNotModified(HTTPRedirection):
-    # @@: but not always (HTTP section 14.18.1)...?
-    # @@: Removed 'date' requirement, as its not required for an ETag
-    # @@: FIXME: This should require either an ETag or a date header
-    code = 304
-    title = 'Not Modified'
-    message = ''
-    # @@: should include date header, optionally other headers
-    # @@: should not return a content body
-    def plain(self, environ):
-        return ''
-    def html(self, environ):
-        """ text/html representation of the exception """
-        return ''
-
-class HTTPUseProxy(_HTTPMove):
-    # @@: OK, not a move, but looks a little like one
-    code = 305
-    title = 'Use Proxy'
-    explanation = (
-        'The resource must be accessed through a proxy '
-        'located at')
-
-class HTTPTemporaryRedirect(_HTTPMove):
-    code = 307
-    title = 'Temporary Redirect'
-
-#
-# 4xx Client Error
-#
-#  The 4xx class of status code is intended for cases in which the client
-#  seems to have erred. Except when responding to a HEAD request, the
-#  server SHOULD include an entity containing an explanation of the error
-#  situation, and whether it is a temporary or permanent condition. These
-#  status codes are applicable to any request method. User agents SHOULD
-#  display any included entity to the user.
-#
-
-class HTTPClientError(HTTPError):
-    """
-    base class for the 400's, where the client is in-error
-
-    This is an error condition in which the client is presumed to be
-    in-error.  This is an expected problem, and thus is not considered
-    a bug.  A server-side traceback is not warranted.  Unless specialized,
-    this is a '400 Bad Request'
-    """
-    code = 400
-    title = 'Bad Request'
-    explanation = ('The server could not comply with the request since\r\n'
-                   'it is either malformed or otherwise incorrect.\r\n')
-
-class HTTPBadRequest(HTTPClientError):
-    pass
-
-class HTTPUnauthorized(HTTPClientError):
-    code = 401
-    title = 'Unauthorized'
-    explanation = (
-        'This server could not verify that you are authorized to\r\n'
-        'access the document you requested.  Either you supplied the\r\n'
-        'wrong credentials (e.g., bad password), or your browser\r\n'
-        'does not understand how to supply the credentials required.\r\n')
-
-class HTTPPaymentRequired(HTTPClientError):
-    code = 402
-    title = 'Payment Required'
-    explanation = ('Access was denied for financial reasons.')
-
-class HTTPForbidden(HTTPClientError):
-    code = 403
-    title = 'Forbidden'
-    explanation = ('Access was denied to this resource.')
-
-class HTTPNotFound(HTTPClientError):
-    code = 404
-    title = 'Not Found'
-    explanation = ('The resource could not be found.')
-
-class HTTPMethodNotAllowed(HTTPClientError):
-    required_headers = ('allow',)
-    code = 405
-    title = 'Method Not Allowed'
-    # override template since we need an environment variable
-    template = ('The method %(REQUEST_METHOD)s is not allowed for '
-                'this resource.\r\n%(detail)s')
-
-class HTTPNotAcceptable(HTTPClientError):
-    code = 406
-    title = 'Not Acceptable'
-    # override template since we need an environment variable
-    template = ('The resource could not be generated that was '
-                'acceptable to your browser (content\r\nof type '
-                '%(HTTP_ACCEPT)s).\r\n%(detail)s')
-
-class HTTPProxyAuthenticationRequired(HTTPClientError):
-    code = 407
-    title = 'Proxy Authentication Required'
-    explanation = ('Authentication /w a local proxy is needed.')
-
-class HTTPRequestTimeout(HTTPClientError):
-    code = 408
-    title = 'Request Timeout'
-    explanation = ('The server has waited too long for the request to '
-                   'be sent by the client.')
-
-class HTTPConflict(HTTPClientError):
-    code = 409
-    title = 'Conflict'
-    explanation = ('There was a conflict when trying to complete '
-                   'your request.')
-
-class HTTPGone(HTTPClientError):
-    code = 410
-    title = 'Gone'
-    explanation = ('This resource is no longer available.  No forwarding '
-                   'address is given.')
-
-class HTTPLengthRequired(HTTPClientError):
-    code = 411
-    title = 'Length Required'
-    explanation = ('Content-Length header required.')
-
-class HTTPPreconditionFailed(HTTPClientError):
-    code = 412
-    title = 'Precondition Failed'
-    explanation = ('Request precondition failed.')
-
-class HTTPRequestEntityTooLarge(HTTPClientError):
-    code = 413
-    title = 'Request Entity Too Large'
-    explanation = ('The body of your request was too large for this server.')
-
-class HTTPRequestURITooLong(HTTPClientError):
-    code = 414
-    title = 'Request-URI Too Long'
-    explanation = ('The request URI was too long for this server.')
-
-class HTTPUnsupportedMediaType(HTTPClientError):
-    code = 415
-    title = 'Unsupported Media Type'
-    # override template since we need an environment variable
-    template = ('The request media type %(CONTENT_TYPE)s is not '
-                'supported by this server.\r\n%(detail)s')
-
-class HTTPRequestRangeNotSatisfiable(HTTPClientError):
-    code = 416
-    title = 'Request Range Not Satisfiable'
-    explanation = ('The Range requested is not available.')
-
-class HTTPExpectationFailed(HTTPClientError):
-    code = 417
-    title = 'Expectation Failed'
-    explanation = ('Expectation failed.')
-
-#
-# 5xx Server Error
-#
-#  Response status codes beginning with the digit "5" indicate cases in
-#  which the server is aware that it has erred or is incapable of
-#  performing the request. Except when responding to a HEAD request, the
-#  server SHOULD include an entity containing an explanation of the error
-#  situation, and whether it is a temporary or permanent condition. User
-#  agents SHOULD display any included entity to the user. These response
-#  codes are applicable to any request method.
-#
-
-class HTTPServerError(HTTPError):
-    """
-    base class for the 500's, where the server is in-error
-
-    This is an error condition in which the server is presumed to be
-    in-error.  This is usually unexpected, and thus requires a traceback;
-    ideally, opening a support ticket for the customer. Unless specialized,
-    this is a '500 Internal Server Error'
-    """
-    code = 500
-    title = 'Internal Server Error'
-    explanation = (
-      'The server has either erred or is incapable of performing\r\n'
-      'the requested operation.\r\n')
-
-class HTTPInternalServerError(HTTPServerError):
-    pass
-
-class HTTPNotImplemented(HTTPServerError):
-    code = 501
-    title = 'Not Implemented'
-    # override template since we need an environment variable
-    template = ('The request method %(REQUEST_METHOD)s is not implemented '
-                'for this server.\r\n%(detail)s')
-
-class HTTPBadGateway(HTTPServerError):
-    code = 502
-    title = 'Bad Gateway'
-    explanation = ('Bad gateway.')
-
-class HTTPServiceUnavailable(HTTPServerError):
-    code = 503
-    title = 'Service Unavailable'
-    explanation = ('The server is currently unavailable. '
-                   'Please try again at a later time.')
-
-class HTTPGatewayTimeout(HTTPServerError):
-    code = 504
-    title = 'Gateway Timeout'
-    explanation = ('The gateway has timed out.')
-
-class HTTPVersionNotSupported(HTTPServerError):
-    code = 505
-    title = 'HTTP Version Not Supported'
-    explanation = ('The HTTP version is not supported.')
-
-# abstract HTTP related exceptions
-__all__ = ['HTTPException', 'HTTPRedirection', 'HTTPError' ]
-
-_exceptions = {}
-for name, value in globals().items():
-    if (isinstance(value, (type, types.ClassType)) and
-        issubclass(value, HTTPException) and
-        value.code):
-        _exceptions[value.code] = value
-        __all__.append(name)
-
-def get_exception(code):
-    return _exceptions[code]
-
-############################################################
-## Middleware implementation:
-############################################################
-
-class HTTPExceptionHandler(object):
-    """
-    catches exceptions and turns them into proper HTTP responses
-
-    Attributes:
-
-       ``warning_level``
-           This attribute determines for what exceptions a stack
-           trace is kept for lower level reporting; by default, it
-           only keeps stack trace for 5xx, HTTPServerError exceptions.
-           To keep a stack trace for 4xx, HTTPClientError exceptions,
-           set this to 400.
-
-    This middleware catches any exceptions (which are subclasses of
-    ``HTTPException``) and turns them into proper HTTP responses.
-    Note if the headers have already been sent, the stack trace is
-    always maintained as this indicates a programming error.
-
-    Note that you must raise the exception before returning the
-    app_iter, and you cannot use this with generator apps that don't
-    raise an exception until after their app_iter is iterated over.
-    """
-
-    def __init__(self, application, warning_level=None):
-        assert not warning_level or ( warning_level > 99 and
-                                      warning_level < 600)
-        self.warning_level = warning_level or 500
-        self.application = application
-
-    def __call__(self, environ, start_response):
-        environ['paste.httpexceptions'] = self
-        environ.setdefault('paste.expected_exceptions',
-                           []).append(HTTPException)
-        try:
-            return self.application(environ, start_response)
-        except HTTPException, exc:
-            return exc(environ, start_response)
-
-def middleware(*args, **kw):
-    import warnings
-    # deprecated 13 dec 2005
-    warnings.warn('httpexceptions.middleware is deprecated; use '
-                  'make_middleware or HTTPExceptionHandler instead',
-                  DeprecationWarning, 2)
-    return make_middleware(*args, **kw)
-
-def make_middleware(app, global_conf=None, warning_level=None):
-    """
-    ``httpexceptions`` middleware; this catches any
-    ``paste.httpexceptions.HTTPException`` exceptions (exceptions like
-    ``HTTPNotFound``, ``HTTPMovedPermanently``, etc) and turns them
-    into proper HTTP responses.
-
-    ``warning_level`` can be an integer corresponding to an HTTP code.
-    Any code over that value will be passed 'up' the chain, potentially
-    reported on by another piece of middleware.
-    """
-    if warning_level:
-        warning_level = int(warning_level)
-    return HTTPExceptionHandler(app, warning_level=warning_level)
-
-__all__.extend(['HTTPExceptionHandler', 'get_exception'])
-
diff --git a/lib/paste/httpheaders.py b/lib/paste/httpheaders.py
@@ -1,1097 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-# (c) 2005 Ian Bicking, Clark C. Evans and contributors
-# This module is part of the Python Paste Project and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-# Some of this code was funded by: http://prometheusresearch.com
-"""
-HTTP Message Header Fields (see RFC 4229)
-
-This contains general support for HTTP/1.1 message headers [1]_ in a
-manner that supports WSGI ``environ`` [2]_ and ``response_headers``
-[3]_. Specifically, this module defines a ``HTTPHeader`` class whose
-instances correspond to field-name items.  The actual field-content for
-the message-header is stored in the appropriate WSGI collection (either
-the ``environ`` for requests, or ``response_headers`` for responses).
-
-Each ``HTTPHeader`` instance is a callable (defining ``__call__``)
-that takes one of the following:
-
-  - an ``environ`` dictionary, returning the corresponding header
-    value by according to the WSGI's ``HTTP_`` prefix mechanism, e.g.,
-    ``USER_AGENT(environ)`` returns ``environ.get('HTTP_USER_AGENT')``
-
-  - a ``response_headers`` list, giving a comma-delimited string for
-    each corresponding ``header_value`` tuple entries (see below).
-
-  - a sequence of string ``*args`` that are comma-delimited into
-    a single string value: ``CONTENT_TYPE("text/html","text/plain")``
-    returns ``"text/html, text/plain"``
-
-  - a set of ``**kwargs`` keyword arguments that are used to create
-    a header value, in a manner dependent upon the particular header in
-    question (to make value construction easier and error-free):
-    ``CONTENT_DISPOSITION(max_age=CONTENT_DISPOSITION.ONEWEEK)``
-    returns ``"public, max-age=60480"``
-
-Each ``HTTPHeader`` instance also provides several methods to act on
-a WSGI collection, for removing and setting header values.
-
-  ``delete(collection)``
-
-    This method removes all entries of the corresponding header from
-    the given collection (``environ`` or ``response_headers``), e.g.,
-    ``USER_AGENT.remove(environ)`` deletes the 'HTTP_USER_AGENT' entry
-    from the ``environ``.
-
-  ``update(collection, *args, **kwargs)``
-
-    This method does an in-place replacement of the given header entry,
-    for example: ``CONTENT_LENGTH(response_headers,len(body))``
-
-    The first argument is a valid ``environ`` dictionary or
-    ``response_headers`` list; remaining arguments are passed on to
-    ``__call__(*args, **kwargs)`` for value construction.
-
-  ``apply(collection, **kwargs)``
-
-    This method is similar to update, only that it may affect other
-    headers.  For example, according to recommendations in RFC 2616,
-    certain Cache-Control configurations should also set the
-    ``Expires`` header for HTTP/1.0 clients. By default, ``apply()``
-    is simply ``update()`` but limited to keyword arguments.
-
-This particular approach to managing headers within a WSGI collection
-has several advantages:
-
-  1. Typos in the header name are easily detected since they become a
-     ``NameError`` when executed.  The approach of using header strings
-     directly can be problematic; for example, the following should
-     return ``None`` : ``environ.get("HTTP_ACCEPT_LANGUAGES")``
-
-  2. For specific headers with validation, using ``__call__`` will
-     result in an automatic header value check.  For example, the
-     _ContentDisposition header will reject a value having ``maxage``
-     or ``max_age`` (the appropriate parameter is ``max-age`` ).
-
-  3. When appending/replacing headers, the field-name has the suggested
-     RFC capitalization (e.g. ``Content-Type`` or ``ETag``) for
-     user-agents that incorrectly use case-sensitive matches.
-
-  4. Some headers (such as ``Content-Type``) are 0, that is,
-     only one entry of this type may occur in a given set of
-     ``response_headers``.  This module knows about those cases and
-     enforces this cardinality constraint.
-
-  5. The exact details of WSGI header management are abstracted so
-     the programmer need not worry about operational differences
-     between ``environ`` dictionary or ``response_headers`` list.
-
-  6. Sorting of ``HTTPHeaders`` is done following the RFC suggestion
-     that general-headers come first, followed by request and response
-     headers, and finishing with entity-headers.
-
-  7. Special care is given to exceptional cases such as Set-Cookie
-     which violates the RFC's recommendation about combining header
-     content into a single entry using comma separation.
-
-A particular difficulty with HTTP message headers is a categorization
-of sorts as described in section 4.2:
-
-    Multiple message-header fields with the same field-name MAY be
-    present in a message if and only if the entire field-value for
-    that header field is defined as a comma-separated list [i.e.,
-    #(values)]. It MUST be possible to combine the multiple header
-    fields into one "field-name: field-value" pair, without changing
-    the semantics of the message, by appending each subsequent
-    field-value to the first, each separated by a comma.
-
-This creates three fundamentally different kinds of headers:
-
-  - Those that do not have a #(values) production, and hence are
-    singular and may only occur once in a set of response fields;
-    this case is handled by the ``_SingleValueHeader`` subclass.
-
-  - Those which have the #(values) production and follow the
-    combining rule outlined above; our ``_MultiValueHeader`` case.
-
-  - Those which are multi-valued, but cannot be combined (such as the
-    ``Set-Cookie`` header due to its ``Expires`` parameter); or where
-    combining them into a single header entry would cause common
-    user-agents to fail (``WWW-Authenticate``, ``Warning``) since
-    they fail to handle dates even when properly quoted. This case
-    is handled by ``_MultiEntryHeader``.
-
-Since this project does not have time to provide rigorous support
-and validation for all headers, it does a basic construction of
-headers listed in RFC 2616 (plus a few others) so that they can
-be obtained by simply doing ``from paste.httpheaders import *``;
-the name of the header instance is the "common name" less any
-dashes to give CamelCase style names.
-
-.. [1] http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
-.. [2] http://www.python.org/peps/pep-0333.html#environ-variables
-.. [3] http://www.python.org/peps/pep-0333.html#the-start-response-callable
-
-"""
-import urllib2
-import re
-from mimetypes import guess_type
-from rfc822 import formatdate, parsedate_tz, mktime_tz
-from time import time as now
-from httpexceptions import HTTPBadRequest
-
-__all__ = ['get_header', 'list_headers', 'normalize_headers',
-           'HTTPHeader', 'EnvironVariable' ]
-
-class EnvironVariable(str):
-    """
-    a CGI ``environ`` variable as described by WSGI
-
-    This is a helper object so that standard WSGI ``environ`` variables
-    can be extracted w/o syntax error possibility.
-    """
-    def __call__(self, environ):
-        return environ.get(self,'')
-    def __repr__(self):
-        return '<EnvironVariable %s>' % self
-    def update(self, environ, value):
-        environ[self] = value
-REMOTE_USER    = EnvironVariable("REMOTE_USER")
-REMOTE_SESSION = EnvironVariable("REMOTE_SESSION")
-AUTH_TYPE      = EnvironVariable("AUTH_TYPE")
-REQUEST_METHOD = EnvironVariable("REQUEST_METHOD")
-SCRIPT_NAME    = EnvironVariable("SCRIPT_NAME")
-PATH_INFO      = EnvironVariable("PATH_INFO")
-
-for _name, _obj in globals().items():
-    if isinstance(_obj, EnvironVariable):
-        __all__.append(_name)
-
-_headers = {}
-
-class HTTPHeader(object):
-    """
-    an HTTP header
-
-    HTTPHeader instances represent a particular ``field-name`` of an
-    HTTP message header. They do not hold a field-value, but instead
-    provide operations that work on is corresponding values.  Storage
-    of the actual field values is done with WSGI ``environ`` or
-    ``response_headers`` as appropriate.  Typically, a sub-classes that
-    represent a specific HTTP header, such as _ContentDisposition, are
-    0.  Once constructed the HTTPHeader instances themselves
-    are immutable and stateless.
-
-    For purposes of documentation a "container" refers to either a
-    WSGI ``environ`` dictionary, or a ``response_headers`` list.
-
-    Member variables (and correspondingly constructor arguments).
-
-      ``name``
-
-          the ``field-name`` of the header, in "common form"
-          as presented in RFC 2616; e.g. 'Content-Type'
-
-      ``category``
-
-          one of 'general', 'request', 'response', or 'entity'
-
-      ``version``
-
-          version of HTTP (informational) with which the header should
-          be recognized
-
-      ``sort_order``
-
-          sorting order to be applied before sorting on
-          field-name when ordering headers in a response
-
-    Special Methods:
-
-       ``__call__``
-
-           The primary method of the HTTPHeader instance is to make
-           it a callable, it takes either a collection, a string value,
-           or keyword arguments and attempts to find/construct a valid
-           field-value
-
-       ``__lt__``
-
-           This method is used so that HTTPHeader objects can be
-           sorted in a manner suggested by RFC 2616.
-
-       ``__str__``
-
-           The string-value for instances of this class is
-           the ``field-name``.
-
-    Primary Methods:
-
-       ``delete()``
-
-           remove the all occurrences (if any) of the given
-           header in the collection provided
-
-       ``update()``
-
-           replaces (if they exist) all field-value items
-           in the given collection with the value provided
-
-       ``tuples()``
-
-           returns a set of (field-name, field-value) tuples
-           5 for extending ``response_headers``
-
-    Custom Methods (these may not be implemented):
-
-       ``apply()``
-
-           similar to ``update``, but with two differences; first,
-           only keyword arguments can be used, and second, specific
-           sub-classes may introduce side-effects
-
-       ``parse()``
-
-           converts a string value of the header into a more usable
-           form, such as time in seconds for a date header, etc.
-
-    The collected versions of initialized header instances are immediately
-    registered and accessible through the ``get_header`` function.  Do not
-    inherit from this directly, use one of ``_SingleValueHeader``,
-    ``_MultiValueHeader``, or ``_MultiEntryHeader`` as appropriate.
-    """
-
-    #
-    # Things which can be customized
-    #
-    version = '1.1'
-    category = 'general'
-    reference = ''
-    extensions = {}
-
-    def compose(self, **kwargs):
-        """
-        build header value from keyword arguments
-
-        This method is used to build the corresponding header value when
-        keyword arguments (or no arguments) were provided.  The result
-        should be a sequence of values.  For example, the ``Expires``
-        header takes a keyword argument ``time`` (e.g. time.time()) from
-        which it returns a the corresponding date.
-        """
-        raise NotImplementedError()
-
-    def parse(self, *args, **kwargs):
-        """
-        convert raw header value into more usable form
-
-        This method invokes ``values()`` with the arguments provided,
-        parses the header results, and then returns a header-specific
-        data structure corresponding to the header.  For example, the
-        ``Expires`` header returns seconds (as returned by time.time())
-        """
-        raise NotImplementedError()
-
-    def apply(self, collection, **kwargs):
-        """
-        update the collection /w header value (may have side effects)
-
-        This method is similar to ``update`` only that usage may result
-        in other headers being changed as recommended by the corresponding
-        specification.  The return value is defined by the particular
-        sub-class. For example, the ``_CacheControl.apply()`` sets the
-        ``Expires`` header in addition to its normal behavior.
-        """
-        self.update(collection, **kwargs)
-
-    #
-    # Things which are standardized (mostly)
-    #
-    def __new__(cls, name, category=None, reference=None, version=None):
-        """
-        construct a new ``HTTPHeader`` instance
-
-        We use the ``__new__`` operator to ensure that only one
-        ``HTTPHeader`` instance exists for each field-name, and to
-        register the header so that it can be found/enumerated.
-        """
-        self = get_header(name, raiseError=False)
-        if self:
-            # Allow the registration to happen again, but assert
-            # that everything is identical.
-            assert self.name == name, \
-                "duplicate registration with different capitalization"
-            assert self.category == category, \
-                "duplicate registration with different category"
-            assert cls == self.__class__, \
-                "duplicate registration with different class"
-            return self
-
-        self = object.__new__(cls)
-        self.name = name
-        assert isinstance(self.name, str)
-        self.category = category or self.category
-        self.version  = version or self.version
-        self.reference = reference or self.reference
-        _headers[self.name.lower()] = self
-        self.sort_order = {'general': 1, 'request': 2,
-                           'response': 3, 'entity': 4 }[self.category]
-        self._environ_name = getattr(self, '_environ_name',
-                                'HTTP_'+ self.name.upper().replace("-","_"))
-        self._headers_name = getattr(self, '_headers_name',
-                                 self.name.lower())
-        assert self.version in ('1.1', '1.0', '0.9')
-        return self
-
-    def __str__(self):
-        return self.name
-
-    def __lt__(self, other):
-        """
-        sort header instances as specified by RFC 2616
-
-        Re-define sorting so that general headers are first, followed
-        by request/response headers, and then entity headers.  The
-        list.sort() methods use the less-than operator for this purpose.
-        """
-        if isinstance(other, HTTPHeader):
-            if self.sort_order != other.sort_order:
-                return self.sort_order < other.sort_order
-            return self.name < other.name
-        return False
-
-    def __repr__(self):
-        ref = self.reference and (' (%s)' % self.reference) or ''
-        return '<%s %s%s>' % (self.__class__.__name__, self.name, ref)
-
-    def values(self, *args, **kwargs):
-        """
-        find/construct field-value(s) for the given header
-
-        Resolution is done according to the following arguments:
-
-        - If only keyword arguments are given, then this is equivalent
-          to ``compose(**kwargs)``.
-
-        - If the first (and only) argument is a dict, it is assumed
-          to be a WSGI ``environ`` and the result of the corresponding
-          ``HTTP_`` entry is returned.
-
-        - If the first (and only) argument is a list, it is assumed
-          to be a WSGI ``response_headers`` and the field-value(s)
-          for this header are collected and returned.
-
-        - In all other cases, the arguments are collected, checked that
-          they are string values, possibly verified by the header's
-          logic, and returned.
-
-        At this time it is an error to provide keyword arguments if args
-        is present (this might change).  It is an error to provide both
-        a WSGI object and also string arguments.  If no arguments are
-        provided, then ``compose()`` is called to provide a default
-        value for the header; if there is not default it is an error.
-        """
-        if not args:
-            return self.compose(**kwargs)
-        if list == type(args[0]):
-            assert 1 == len(args)
-            result = []
-            name = self.name.lower()
-            for value in [value for header, value in args[0]
-                         if header.lower() == name]:
-                result.append(value)
-            return result
-        if dict == type(args[0]):
-            assert 1 == len(args) and 'wsgi.version' in args[0]
-            value = args[0].get(self._environ_name)
-            if not value:
-                return ()
-            return (value,)
-        for item in args:
-            assert not type(item) in (dict, list)
-        return args
-
-    def __call__(self, *args, **kwargs):
-        """
-        converts ``values()`` into a string value
-
-        This method converts the results of ``values()`` into a string
-        value for common usage.  By default, it is asserted that only
-        one value exists; if you need to access all values then either
-        call ``values()`` directly, or inherit ``_MultiValueHeader``
-        which overrides this method to return a comma separated list of
-        values as described by section 4.2 of RFC 2616.
-        """
-        values = self.values(*args, **kwargs)
-        assert isinstance(values, (tuple, list))
-        if not values:
-            return ''
-        assert len(values) == 1, "more than one value: %s" % repr(values)
-        return str(values[0]).strip()
-
-    def delete(self, collection):
-        """
-        removes all occurances of the header from the collection provided
-        """
-        if type(collection) == dict:
-            if self._environ_name in collection:
-                del collection[self._environ_name]
-            return self
-        assert list == type(collection)
-        i = 0
-        while i < len(collection):
-            if collection[i][0].lower() == self._headers_name:
-                del collection[i]
-                continue
-            i += 1
-
-    def update(self, collection, *args, **kwargs):
-        """
-        updates the collection with the provided header value
-
-        This method replaces (in-place when possible) all occurrences of
-        the given header with the provided value.  If no value is
-        provided, this is the same as ``remove`` (note that this case
-        can only occur if the target is a collection w/o a corresponding
-        header value). The return value is the new header value (which
-        could be a list for ``_MultiEntryHeader`` instances).
-        """
-        value = self.__call__(*args, **kwargs)
-        if not value:
-            self.remove(collection)
-            return
-        if type(collection) == dict:
-            collection[self._environ_name] = value
-            return
-        assert list == type(collection)
-        i = 0
-        found = False
-        while i < len(collection):
-            if collection[i][0].lower() == self._headers_name:
-                if found:
-                    del collection[i]
-                    continue
-                collection[i] = (self.name, value)
-                found = True
-            i += 1
-        if not found:
-            collection.append((self.name, value))
-
-    def tuples(self, *args, **kwargs):
-        value = self.__call__(*args, **kwargs)
-        if not value:
-            return ()
-        return [(self.name, value)]
-
-class _SingleValueHeader(HTTPHeader):
-    """
-    a ``HTTPHeader`` with exactly a single value
-
-    This is the default behavior of ``HTTPHeader`` where returning a
-    the string-value of headers via ``__call__`` assumes that only
-    a single value exists.
-    """
-    pass
-
-class _MultiValueHeader(HTTPHeader):
-    """
-    a ``HTTPHeader`` with one or more values
-
-    The field-value for these header instances is is allowed to be more
-    than one value; whereby the ``__call__`` method returns a comma
-    separated list as described by section 4.2 of RFC 2616.
-    """
-
-    def __call__(self, *args, **kwargs):
-        results = self.values(*args, **kwargs)
-        if not results:
-            return ''
-        return ", ".join([str(v).strip() for v in results])
-
-    def parse(self, *args, **kwargs):
-        value = self.__call__(*args, **kwargs)
-        values = value.split(',')
-        return [
-            v.strip() for v in values
-            if v.strip()]
-
-class _MultiEntryHeader(HTTPHeader):
-    """
-    a multi-value ``HTTPHeader`` where items cannot be combined with a comma
-
-    This header is multi-valued, but the values should not be combined
-    with a comma since the header is not in compliance with RFC 2616
-    (Set-Cookie due to Expires parameter) or which common user-agents do
-    not behave well when the header values are combined.
-    """
-
-    def update(self, collection, *args, **kwargs):
-        assert list == type(collection), "``environ`` may not be updated"
-        self.delete(collection)
-        collection.extend(self.tuples(*args, **kwargs))
-
-    def tuples(self, *args, **kwargs):
-        values = self.values(*args, **kwargs)
-        if not values:
-            return ()
-        return [(self.name, value.strip()) for value in values]
-
-def get_header(name, raiseError=True):
-    """
-    find the given ``HTTPHeader`` instance
-
-    This function finds the corresponding ``HTTPHeader`` for the
-    ``name`` provided.  So that python-style names can be used,
-    underscores are converted to dashes before the lookup.
-    """
-    retval = _headers.get(str(name).strip().lower().replace("_","-"))
-    if not retval and raiseError:
-        raise AssertionError("'%s' is an unknown header" % name)
-    return retval
-
-def list_headers(general=None, request=None, response=None, entity=None):
-    " list all headers for a given category "
-    if not (general or request or response or entity):
-        general = request = response = entity = True
-    search = []
-    for (bool, strval) in ((general, 'general'), (request, 'request'),
-                           (response, 'response'), (entity, 'entity')):
-        if bool:
-            search.append(strval)
-    return [head for head in _headers.values() if head.category in search]
-
-def normalize_headers(response_headers, strict=True):
-    """
-    sort headers as suggested by  RFC 2616
-
-    This alters the underlying response_headers to use the common
-    name for each header; as well as sorting them with general
-    headers first, followed by request/response headers, then
-    entity headers, and unknown headers last.
-    """
-    category = {}
-    for idx in range(len(response_headers)):
-        (key, val) = response_headers[idx]
-        head = get_header(key, strict)
-        if not head:
-            newhead = '-'.join([x.capitalize() for x in 
-                                key.replace("_","-").split("-")])
-            response_headers[idx] = (newhead, val)
-            category[newhead] = 4
-            continue
-        response_headers[idx] = (str(head), val)
-        category[str(head)] = head.sort_order
-    def compare(a, b):
-        ac = category[a[0]]
-        bc = category[b[0]]
-        if ac == bc:
-            return cmp(a[0], b[0])
-        return cmp(ac, bc)
-    response_headers.sort(compare)
-
-class _DateHeader(_SingleValueHeader):
-    """
-    handle date-based headers
-
-    This extends the ``_SingleValueHeader`` object with specific
-    treatment of time values:
-
-    - It overrides ``compose`` to provide a sole keyword argument
-      ``time`` which is an offset in seconds from the current time.
-
-    - A ``time`` method is provided which parses the given value
-      and returns the current time value.
-    """
-
-    def compose(self, time=None, delta=None):
-        time = time or now()
-        if delta:
-            assert type(delta) == int
-            time += delta
-        return (formatdate(time),)
-
-    def parse(self, *args, **kwargs):
-        """ return the time value (in seconds since 1970) """
-        value = self.__call__(*args, **kwargs)
-        if value:
-            try:
-                return mktime_tz(parsedate_tz(value))
-            except TypeError:
-                raise HTTPBadRequest((
-                    "Received an ill-formed timestamp for %s: %s\r\n") %
-                    (self.name, value))
-
-#
-# Following are specific HTTP headers. Since these classes are mostly
-# singletons, there is no point in keeping the class around once it has
-# been instantiated, so we use the same name.
-#
-
-class _CacheControl(_MultiValueHeader):
-    """
-    Cache-Control, RFC 2616 14.9  (use ``CACHE_CONTROL``)
-
-    This header can be constructed (using keyword arguments), by
-    first specifying one of the following mechanisms:
-
-      ``public``
-
-          if True, this argument specifies that the
-          response, as a whole, may be cashed.
-
-      ``private``
-
-          if True, this argument specifies that the response, as a
-          whole, may be cashed; this implementation does not support
-          the enumeration of private fields
-
-      ``no_cache``
-
-          if True, this argument specifies that the response, as a
-          whole, may not be cashed; this implementation does not
-          support the enumeration of private fields
-
-    In general, only one of the above three may be True, the other 2
-    must then be False or None.  If all three are None, then the cache
-    is assumed to be ``public``.  Following one of these mechanism
-    specifiers are various modifiers:
-
-      ``no_store``
-
-          indicates if content may be stored on disk;
-          otherwise cache is limited to memory (note:
-          users can still save the data, this applies
-          to intermediate caches)
-
-      ``max_age``
-
-          the maximum duration (in seconds) for which
-          the content should be cached; if ``no-cache``
-          is specified, this defaults to 0 seconds
-
-      ``s_maxage``
-
-          the maximum duration (in seconds) for which the
-          content should be allowed in a shared cache.
-
-      ``no_transform``
-
-          specifies that an intermediate cache should
-          not convert the content from one type to
-          another (e.g. transform a BMP to a PNG).
-
-      ``extensions``
-
-          gives additional cache-control extensions,
-          such as items like, community="UCI" (14.9.6)
-
-    The usage of ``apply()`` on this header has side-effects. As
-    recommended by RFC 2616, if ``max_age`` is provided, then then the
-    ``Expires`` header is also calculated for HTTP/1.0 clients and
-    proxies (this is done at the time ``apply()`` is called).  For
-    ``no-cache`` and for ``private`` cases, we either do not want the
-    response cached or do not want any response accidently returned to
-    other users; so to prevent this case, we set the ``Expires`` header
-    to the time of the request, signifying to HTTP/1.0 transports that
-    the content isn't to be cached.  If you are using SSL, your
-    communication is already "private", so to work with HTTP/1.0
-    browsers over SSL, consider specifying your cache as ``public`` as
-    the distinction between public and private is moot.
-    """
-
-    # common values for max-age; "good enough" approximates
-    ONE_HOUR  = 60*60
-    ONE_DAY   = ONE_HOUR * 24
-    ONE_WEEK  = ONE_DAY * 7
-    ONE_MONTH = ONE_DAY * 30
-    ONE_YEAR  = ONE_WEEK * 52
-
-    def _compose(self, public=None, private=None, no_cache=None,
-                 no_store=False, max_age=None, s_maxage=None,
-                 no_transform=False, **extensions):
-        assert isinstance(max_age, (type(None), int))
-        assert isinstance(s_maxage, (type(None), int))
-        expires = 0
-        result = []
-        if private is True:
-            assert not public and not no_cache and not s_maxage
-            result.append('private')
-        elif no_cache is True:
-            assert not public and not private and not max_age
-            result.append('no-cache')
-        else:
-            assert public is None or public is True
-            assert not private and not no_cache
-            expires = max_age
-            result.append('public')
-        if no_store:
-            result.append('no-store')
-        if no_transform:
-            result.append('no-transform')
-        if max_age is not None:
-            result.append('max-age=%d' % max_age)
-        if s_maxage is not None:
-            result.append('s-maxage=%d' % s_maxage)
-        for (k, v) in extensions.items():
-            if k not in self.extensions:
-                raise AssertionError("unexpected extension used: '%s'" % k)
-            result.append('%s="%s"' % (k.replace("_", "-"), v))
-        return (result, expires)
-
-    def compose(self, **kwargs):
-        (result, expires) = self._compose(**kwargs)
-        return result
-
-    def apply(self, collection, **kwargs):
-        """ returns the offset expiration in seconds """
-        (result, expires) = self._compose(**kwargs)
-        if expires is not None:
-            EXPIRES.update(collection, delta=expires)
-        self.update(collection, *result)
-        return expires
-
-_CacheControl('Cache-Control', 'general', 'RFC 2616, 14.9')
-
-class _ContentType(_SingleValueHeader):
-    """
-    Content-Type, RFC 2616 section 14.17
-
-    Unlike other headers, use the CGI variable instead.
-    """
-    version = '1.0'
-    _environ_name = 'CONTENT_TYPE'
-
-    # common mimetype constants
-    UNKNOWN    = 'application/octet-stream'
-    TEXT_PLAIN = 'text/plain'
-    TEXT_HTML  = 'text/html'
-    TEXT_XML   = 'text/xml'
-
-    def compose(self, major=None, minor=None, charset=None):
-        if not major:
-            if minor in ('plain', 'html', 'xml'):
-                major = 'text'
-            else:
-                assert not minor and not charset
-                return (self.UNKNOWN,)
-        if not minor:
-            minor = "*"
-        result = "%s/%s" % (major, minor)
-        if charset:
-            result += "; charset=%s" % charset
-        return (result,)
-
-_ContentType('Content-Type', 'entity', 'RFC 2616, 14.17')
-
-class _ContentLength(_SingleValueHeader):
-    """
-    Content-Length, RFC 2616 section 14.13
-
-    Unlike other headers, use the CGI variable instead.
-    """
-    version = "1.0"
-    _environ_name = 'CONTENT_LENGTH'
-
-_ContentLength('Content-Length', 'entity', 'RFC 2616, 14.13')
-
-class _ContentDisposition(_SingleValueHeader):
-    """
-    Content-Disposition, RFC 2183 (use ``CONTENT_DISPOSITION``)
-
-    This header can be constructed (using keyword arguments),
-    by first specifying one of the following mechanisms:
-
-      ``attachment``
-
-          if True, this specifies that the content should not be
-          shown in the browser and should be handled externally,
-          even if the browser could render the content
-
-      ``inline``
-
-         exclusive with attachment; indicates that the content
-         should be rendered in the browser if possible, but
-         otherwise it should be handled externally
-
-    Only one of the above 2 may be True.  If both are None, then
-    the disposition is assumed to be an ``attachment``. These are
-    distinct fields since support for field enumeration may be
-    added in the future.
-
-      ``filename``
-
-          the filename parameter, if any, to be reported; if
-          this is None, then the current object's filename
-          attribute is used
-
-    The usage of ``apply()`` on this header has side-effects. If
-    filename is provided, and Content-Type is not set or is
-    'application/octet-stream', then the mimetypes.guess is used to
-    upgrade the Content-Type setting.
-    """
-
-    def _compose(self, attachment=None, inline=None, filename=None):
-        result = []
-        if inline is True:
-            assert not attachment
-            result.append('inline')
-        else:
-            assert not inline
-            result.append('attachment')
-        if filename:
-            assert '"' not in filename
-            filename = filename.split("/")[-1]
-            filename = filename.split("\\")[-1]
-            result.append('filename="%s"' % filename)
-        return (("; ".join(result),), filename)
-
-    def compose(self, **kwargs):
-        (result, mimetype) = self._compose(**kwargs)
-        return result
-
-    def apply(self, collection, **kwargs):
-        """ return the new Content-Type side-effect value """
-        (result, filename) = self._compose(**kwargs)
-        mimetype = CONTENT_TYPE(collection)
-        if filename and (not mimetype or CONTENT_TYPE.UNKNOWN == mimetype):
-            mimetype, _ = guess_type(filename)
-            if mimetype and CONTENT_TYPE.UNKNOWN != mimetype:
-                CONTENT_TYPE.update(collection, mimetype)
-        self.update(collection, *result)
-        return mimetype
-
-_ContentDisposition('Content-Disposition', 'entity', 'RFC 2183')
-
-class _IfModifiedSince(_DateHeader):
-    """
-    If-Modified-Since, RFC 2616 section 14.25
-    """
-    version = '1.0'
-
-    def __call__(self, *args, **kwargs):
-        """
-        Split the value on ';' incase the header includes extra attributes. E.g.
-        IE 6 is known to send:
-        If-Modified-Since: Sun, 25 Jun 2006 20:36:35 GMT; length=1506
-        """
-        return _DateHeader.__call__(self, *args, **kwargs).split(';', 1)[0]
-
-    def parse(self, *args, **kwargs):
-        value = _DateHeader.parse(self, *args, **kwargs)
-        if value and value > now():
-            raise HTTPBadRequest((
-              "Please check your system clock.\r\n"
-              "According to this server, the time provided in the\r\n"
-              "%s header is in the future.\r\n") % self.name)
-        return value
-_IfModifiedSince('If-Modified-Since', 'request', 'RFC 2616, 14.25')
-
-class _Range(_MultiValueHeader):
-    """
-    Range, RFC 2616 14.35 (use ``RANGE``)
-
-    According to section 14.16, the response to this message should be a
-    206 Partial Content and that if multiple non-overlapping byte ranges
-    are requested (it is an error to request multiple overlapping
-    ranges) the result should be sent as multipart/byteranges mimetype.
-
-    The server should respond with '416 Requested Range Not Satisfiable'
-    if the requested ranges are out-of-bounds.  The specification also
-    indicates that a syntax error in the Range request should result in
-    the header being ignored rather than a '400 Bad Request'.
-    """
-
-    def parse(self, *args, **kwargs):
-        """
-        Returns a tuple (units, list), where list is a sequence of
-        (begin, end) tuples; and end is None if it was not provided.
-        """
-        value = self.__call__(*args, **kwargs)
-        if not value:
-            return None
-        ranges = []
-        last_end   = -1
-        try:
-            (units, range) = value.split("=", 1)
-            units = units.strip().lower()
-            for item in range.split(","):
-                (begin, end) = item.split("-")
-                if not begin.strip():
-                    begin = 0
-                else:
-                    begin = int(begin)
-                if begin <= last_end:
-                    raise ValueError()
-                if not end.strip():
-                    end = None
-                else:
-                    end = int(end)
-                last_end = end
-                ranges.append((begin, end))
-        except ValueError:
-            # In this case where the Range header is malformed,
-            # section 14.16 says to treat the request as if the
-            # Range header was not present.  How do I log this?
-            return None
-        return (units, ranges)
-_Range('Range', 'request', 'RFC 2616, 14.35')
-
-class _AcceptLanguage(_MultiValueHeader):
-    """
-    Accept-Language, RFC 2616 section 14.4
-    """
-
-    def parse(self, *args, **kwargs):
-        """
-        Return a list of language tags sorted by their "q" values.  For example,
-        "en-us,en;q=0.5" should return ``["en-us", "en"]``.  If there is no
-        ``Accept-Language`` header present, default to ``[]``.
-        """
-        header = self.__call__(*args, **kwargs)
-        if header is None:
-            return []
-        langs = [v for v in header.split(",") if v]
-        qs = []
-        for lang in langs:
-            pieces = lang.split(";")
-            lang, params = pieces[0].strip().lower(), pieces[1:]
-            q = 1
-            for param in params:
-                if '=' not in param:
-                    # Malformed request; probably a bot, we'll ignore
-                    continue
-                lvalue, rvalue = param.split("=")
-                lvalue = lvalue.strip().lower()
-                rvalue = rvalue.strip()
-                if lvalue == "q":
-                    q = float(rvalue)
-            qs.append((lang, q))
-        qs.sort(lambda a, b: -cmp(a[1], b[1]))
-        return [lang for (lang, q) in qs]
-_AcceptLanguage('Accept-Language', 'request', 'RFC 2616, 14.4')
-
-class _AcceptRanges(_MultiValueHeader):
-    """
-    Accept-Ranges, RFC 2616 section 14.5
-    """
-    def compose(self, none=None, bytes=None):
-        if bytes:
-            return ('bytes',)
-        return ('none',)
-_AcceptRanges('Accept-Ranges', 'response', 'RFC 2616, 14.5')
-
-class _ContentRange(_SingleValueHeader):
-    """
-    Content-Range, RFC 2616 section 14.6
-    """
-    def compose(self, first_byte=None, last_byte=None, total_length=None):
-        retval = "bytes %d-%d/%d" % (first_byte, last_byte, total_length)
-        assert last_byte == -1 or first_byte <= last_byte
-        assert last_byte  < total_length
-        return (retval,)
-_ContentRange('Content-Range', 'entity', 'RFC 2616, 14.6')
-
-class _Authorization(_SingleValueHeader):
-    """
-    Authorization, RFC 2617 (RFC 2616, 14.8)
-    """
-    def compose(self, digest=None, basic=None, username=None, password=None,
-                challenge=None, path=None, method=None):
-        assert username and password
-        if basic or not challenge:
-            assert not digest
-            userpass = "%s:%s" % (username.strip(), password.strip())
-            return "Basic %s" % userpass.encode('base64').strip()
-        assert challenge and not basic
-        path = path or "/"
-        (_, realm) = challenge.split('realm="')
-        (realm, _) = realm.split('"', 1)
-        auth = urllib2.AbstractDigestAuthHandler()
-        auth.add_password(realm, path, username, password)
-        (token, challenge) = challenge.split(' ', 1)
-        chal = urllib2.parse_keqv_list(urllib2.parse_http_list(challenge))
-        class FakeRequest(object):
-            def get_full_url(self):
-                return path
-            def has_data(self):
-                return False
-            def get_method(self):
-                return method or "GET"
-            get_selector = get_full_url
-        retval = "Digest %s" % auth.get_authorization(FakeRequest(), chal)
-        return (retval,)
-_Authorization('Authorization', 'request', 'RFC 2617')
-
-#
-# For now, construct a minimalistic version of the field-names; at a
-# later date more complicated headers may sprout content constructors.
-# The items commented out have concrete variants.
-#
-for (name,              category, version, style,      comment) in \
-(("Accept"             ,'request' ,'1.1','multi-value','RFC 2616, 14.1' )
-,("Accept-Charset"     ,'request' ,'1.1','multi-value','RFC 2616, 14.2' )
-,("Accept-Encoding"    ,'request' ,'1.1','multi-value','RFC 2616, 14.3' )
-#,("Accept-Language"    ,'request' ,'1.1','multi-value','RFC 2616, 14.4' )
-#,("Accept-Ranges"      ,'response','1.1','multi-value','RFC 2616, 14.5' )
-,("Age"                ,'response','1.1','singular'   ,'RFC 2616, 14.6' )
-,("Allow"              ,'entity'  ,'1.0','multi-value','RFC 2616, 14.7' )
-#,("Authorization"      ,'request' ,'1.0','singular'   ,'RFC 2616, 14.8' )
-#,("Cache-Control"      ,'general' ,'1.1','multi-value','RFC 2616, 14.9' )
-,("Cookie"             ,'request' ,'1.0','multi-value','RFC 2109/Netscape')
-,("Connection"         ,'general' ,'1.1','multi-value','RFC 2616, 14.10')
-,("Content-Encoding"   ,'entity'  ,'1.0','multi-value','RFC 2616, 14.11')
-#,("Content-Disposition",'entity'  ,'1.1','multi-value','RFC 2616, 15.5' )
-,("Content-Language"   ,'entity'  ,'1.1','multi-value','RFC 2616, 14.12')
-#,("Content-Length"     ,'entity'  ,'1.0','singular'   ,'RFC 2616, 14.13')
-,("Content-Location"   ,'entity'  ,'1.1','singular'   ,'RFC 2616, 14.14')
-,("Content-MD5"        ,'entity'  ,'1.1','singular'   ,'RFC 2616, 14.15')
-#,("Content-Range"      ,'entity'  ,'1.1','singular'   ,'RFC 2616, 14.16')
-#,("Content-Type"       ,'entity'  ,'1.0','singular'   ,'RFC 2616, 14.17')
-,("Date"               ,'general' ,'1.0','date-header','RFC 2616, 14.18')
-,("ETag"               ,'response','1.1','singular'   ,'RFC 2616, 14.19')
-,("Expect"             ,'request' ,'1.1','multi-value','RFC 2616, 14.20')
-,("Expires"            ,'entity'  ,'1.0','date-header','RFC 2616, 14.21')
-,("From"               ,'request' ,'1.0','singular'   ,'RFC 2616, 14.22')
-,("Host"               ,'request' ,'1.1','singular'   ,'RFC 2616, 14.23')
-,("If-Match"           ,'request' ,'1.1','multi-value','RFC 2616, 14.24')
-#,("If-Modified-Since"  ,'request' ,'1.0','date-header','RFC 2616, 14.25')
-,("If-None-Match"      ,'request' ,'1.1','multi-value','RFC 2616, 14.26')
-,("If-Range"           ,'request' ,'1.1','singular'   ,'RFC 2616, 14.27')
-,("If-Unmodified-Since",'request' ,'1.1','date-header' ,'RFC 2616, 14.28')
-,("Last-Modified"      ,'entity'  ,'1.0','date-header','RFC 2616, 14.29')
-,("Location"           ,'response','1.0','singular'   ,'RFC 2616, 14.30')
-,("Max-Forwards"       ,'request' ,'1.1','singular'   ,'RFC 2616, 14.31')
-,("Pragma"             ,'general' ,'1.0','multi-value','RFC 2616, 14.32')
-,("Proxy-Authenticate" ,'response','1.1','multi-value','RFC 2616, 14.33')
-,("Proxy-Authorization",'request' ,'1.1','singular'   ,'RFC 2616, 14.34')
-#,("Range"              ,'request' ,'1.1','multi-value','RFC 2616, 14.35')
-,("Referer"            ,'request' ,'1.0','singular'   ,'RFC 2616, 14.36')
-,("Retry-After"        ,'response','1.1','singular'   ,'RFC 2616, 14.37')
-,("Server"             ,'response','1.0','singular'   ,'RFC 2616, 14.38')
-,("Set-Cookie"         ,'response','1.0','multi-entry','RFC 2109/Netscape')
-,("TE"                 ,'request' ,'1.1','multi-value','RFC 2616, 14.39')
-,("Trailer"            ,'general' ,'1.1','multi-value','RFC 2616, 14.40')
-,("Transfer-Encoding"  ,'general' ,'1.1','multi-value','RFC 2616, 14.41')
-,("Upgrade"            ,'general' ,'1.1','multi-value','RFC 2616, 14.42')
-,("User-Agent"         ,'request' ,'1.0','singular'   ,'RFC 2616, 14.43')
-,("Vary"               ,'response','1.1','multi-value','RFC 2616, 14.44')
-,("Via"                ,'general' ,'1.1','multi-value','RFC 2616, 14.45')
-,("Warning"            ,'general' ,'1.1','multi-entry','RFC 2616, 14.46')
-,("WWW-Authenticate"   ,'response','1.0','multi-entry','RFC 2616, 14.47')):
-    klass = {'multi-value': _MultiValueHeader,
-             'multi-entry': _MultiEntryHeader,
-             'date-header': _DateHeader,
-             'singular'   : _SingleValueHeader}[style]
-    klass(name, category, comment, version).__doc__ = comment
-    del klass
-
-for head in _headers.values():
-    headname = head.name.replace("-","_").upper()
-    locals()[headname] = head
-    __all__.append(headname)
-
-__pudge_all__ = __all__[:]
-for _name, _obj in globals().items():
-    if isinstance(_obj, type) and issubclass(_obj, HTTPHeader):
-        __pudge_all__.append(_name)
diff --git a/lib/paste/httpserver.py b/lib/paste/httpserver.py
@@ -1,1406 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-# (c) 2005 Clark C. Evans
-# This module is part of the Python Paste Project and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-# This code was written with funding by http://prometheusresearch.com
-"""
-WSGI HTTP Server
-
-This is a minimalistic WSGI server using Python's built-in BaseHTTPServer;
-if pyOpenSSL is installed, it also provides SSL capabilities.
-"""
-
-# @@: add in protection against HTTP/1.0 clients who claim to
-#     be 1.1 but do not send a Content-Length
-
-# @@: add support for chunked encoding, this is not a 1.1 server
-#     till this is completed.
-
-import atexit
-import traceback
-import socket, sys, threading, urlparse, Queue, urllib
-import posixpath
-import time
-import thread
-import os
-from itertools import count
-from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
-from SocketServer import ThreadingMixIn
-from paste.util import converters
-import logging
-try:
-    from paste.util import killthread
-except ImportError:
-    # Not available, probably no ctypes
-    killthread = None
-
-__all__ = ['WSGIHandlerMixin', 'WSGIServer', 'WSGIHandler', 'serve']
-__version__ = "0.5"
-
-class ContinueHook(object):
-    """
-    When a client request includes a 'Expect: 100-continue' header, then
-    it is the responsibility of the server to send 100 Continue when it
-    is ready for the content body.  This allows authentication, access
-    levels, and other exceptions to be detected *before* bandwith is
-    spent on the request body.
-
-    This is a rfile wrapper that implements this functionality by
-    sending 100 Continue to the client immediately after the user
-    requests the content via a read() operation on the rfile stream.
-    After this response is sent, it becomes a pass-through object.
-    """
-
-    def __init__(self, rfile, write):
-        self._ContinueFile_rfile = rfile
-        self._ContinueFile_write = write
-        for attr in ('close', 'closed', 'fileno', 'flush',
-                     'mode', 'bufsize', 'softspace'):
-            if hasattr(rfile, attr):
-                setattr(self, attr, getattr(rfile, attr))
-        for attr in ('read', 'readline', 'readlines'):
-            if hasattr(rfile, attr):
-                setattr(self, attr, getattr(self, '_ContinueFile_' + attr))
-
-    def _ContinueFile_send(self):
-        self._ContinueFile_write("HTTP/1.1 100 Continue\r\n\r\n")
-        rfile = self._ContinueFile_rfile
-        for attr in ('read', 'readline', 'readlines'):
-            if hasattr(rfile, attr):
-                setattr(self, attr, getattr(rfile, attr))
-
-    def _ContinueFile_read(self, size=-1):
-        self._ContinueFile_send()
-        return self._ContinueFile_rfile.readline(size)
-
-    def _ContinueFile_readline(self, size=-1):
-        self._ContinueFile_send()
-        return self._ContinueFile_rfile.readline(size)
-
-    def _ContinueFile_readlines(self, sizehint=0):
-        self._ContinueFile_send()
-        return self._ContinueFile_rfile.readlines(sizehint)
-
-class WSGIHandlerMixin:
-    """
-    WSGI mix-in for HTTPRequestHandler
-
-    This class is a mix-in to provide WSGI functionality to any
-    HTTPRequestHandler derivative (as provided in Python's BaseHTTPServer).
-    This assumes a ``wsgi_application`` handler on ``self.server``.
-    """
-    lookup_addresses = True
-
-    def log_request(self, *args, **kwargs):
-        """ disable success request logging
-
-        Logging transactions should not be part of a WSGI server,
-        if you want logging; look at paste.translogger
-        """
-        pass
-
-    def log_message(self, *args, **kwargs):
-        """ disable error message logging
-
-        Logging transactions should not be part of a WSGI server,
-        if you want logging; look at paste.translogger
-        """
-        pass
-
-    def version_string(self):
-        """ behavior that BaseHTTPServer should have had """
-        if not self.sys_version:
-            return self.server_version
-        else:
-            return self.server_version + ' ' + self.sys_version
-
-    def wsgi_write_chunk(self, chunk):
-        """
-        Write a chunk of the output stream; send headers if they
-        have not already been sent.
-        """
-        if not self.wsgi_headers_sent and not self.wsgi_curr_headers:
-            raise RuntimeError(
-                "Content returned before start_response called")
-        if not self.wsgi_headers_sent:
-            self.wsgi_headers_sent = True
-            (status, headers) = self.wsgi_curr_headers
-            code, message = status.split(" ", 1)
-            self.send_response(int(code), message)
-            #
-            # HTTP/1.1 compliance; either send Content-Length or
-            # signal that the connection is being closed.
-            #
-            send_close = True
-            for (k, v) in  headers:
-                lk = k.lower()
-                if 'content-length' == lk:
-                    send_close = False
-                if 'connection' == lk:
-                    if 'close' == v.lower():
-                        self.close_connection = 1
-                        send_close = False
-                self.send_header(k, v)
-            if send_close:
-                self.close_connection = 1
-                self.send_header('Connection', 'close')
-
-            self.end_headers()
-        self.wfile.write(chunk)
-
-    def wsgi_start_response(self, status, response_headers, exc_info=None):
-        if exc_info:
-            try:
-                if self.wsgi_headers_sent:
-                    raise exc_info[0], exc_info[1], exc_info[2]
-                else:
-                    # In this case, we're going to assume that the
-                    # higher-level code is currently handling the
-                    # issue and returning a resonable response.
-                    # self.log_error(repr(exc_info))
-                    pass
-            finally:
-                exc_info = None
-        elif self.wsgi_curr_headers:
-            assert 0, "Attempt to set headers a second time w/o an exc_info"
-        self.wsgi_curr_headers = (status, response_headers)
-        return self.wsgi_write_chunk
-
-    def wsgi_setup(self, environ=None):
-        """
-        Setup the member variables used by this WSGI mixin, including
-        the ``environ`` and status member variables.
-
-        After the basic environment is created; the optional ``environ``
-        argument can be used to override any settings.
-        """
-
-        (scheme, netloc, path, query, fragment) = urlparse.urlsplit(self.path)
-        path = urllib.unquote(path)
-        endslash = path.endswith('/')
-        path = posixpath.normpath(path)
-        if endslash and path != '/':
-            # Put the slash back...
-            path += '/'
-        (server_name, server_port) = self.server.server_address
-
-        rfile = self.rfile
-        if 'HTTP/1.1' == self.protocol_version and \
-                '100-continue' == self.headers.get('Expect','').lower():
-            rfile = ContinueHook(rfile, self.wfile.write)
-        else:
-            # We can put in the protection to keep from over-reading the
-            # file
-            try:
-                content_length = int(self.headers.get('Content-Length', '0'))
-            except ValueError:
-                content_length = 0
-            if not hasattr(self.connection, 'get_context'):
-                # @@: LimitedLengthFile is currently broken in connection
-                # with SSL (sporatic errors that are diffcult to trace, but
-                # ones that go away when you don't use LimitedLengthFile)
-                rfile = LimitedLengthFile(rfile, content_length)
-
-        remote_address = self.client_address[0]
-        self.wsgi_environ = {
-                'wsgi.version': (1,0)
-               ,'wsgi.url_scheme': 'http'
-               ,'wsgi.input': rfile
-               ,'wsgi.errors': sys.stderr
-               ,'wsgi.multithread': True
-               ,'wsgi.multiprocess': False
-               ,'wsgi.run_once': False
-               # CGI variables required by PEP-333
-               ,'REQUEST_METHOD': self.command
-               ,'SCRIPT_NAME': '' # application is root of server
-               ,'PATH_INFO': path
-               ,'QUERY_STRING': query
-               ,'CONTENT_TYPE': self.headers.get('Content-Type', '')
-               ,'CONTENT_LENGTH': self.headers.get('Content-Length', '0')
-               ,'SERVER_NAME': server_name
-               ,'SERVER_PORT': str(server_port)
-               ,'SERVER_PROTOCOL': self.request_version
-               # CGI not required by PEP-333
-               ,'REMOTE_ADDR': remote_address
-               }
-        if scheme:
-            self.wsgi_environ['paste.httpserver.proxy.scheme'] = scheme
-        if netloc:
-            self.wsgi_environ['paste.httpserver.proxy.host'] = netloc
-
-        if self.lookup_addresses:
-            # @@: make lookup_addreses actually work, at this point
-            #     it has been address_string() is overriden down in
-            #     file and hence is a noop
-            if remote_address.startswith("192.168.") \
-            or remote_address.startswith("10.") \
-            or remote_address.startswith("172.16."):
-                pass
-            else:
-                address_string = None # self.address_string()
-                if address_string:
-                    self.wsgi_environ['REMOTE_HOST'] = address_string
-
-        if hasattr(self.server, 'thread_pool'):
-            # Now that we know what the request was for, we should
-            # tell the thread pool what its worker is working on
-            self.server.thread_pool.worker_tracker[thread.get_ident()][1] = self.wsgi_environ
-            self.wsgi_environ['paste.httpserver.thread_pool'] = self.server.thread_pool
-
-        for k, v in self.headers.items():
-            key = 'HTTP_' + k.replace("-","_").upper()
-            if key in ('HTTP_CONTENT_TYPE','HTTP_CONTENT_LENGTH'):
-                continue
-            self.wsgi_environ[key] = ','.join(self.headers.getheaders(k))
-
-        if hasattr(self.connection,'get_context'):
-            self.wsgi_environ['wsgi.url_scheme'] = 'https'
-            # @@: extract other SSL parameters from pyOpenSSL at...
-            # http://www.modssl.org/docs/2.8/ssl_reference.html#ToC25
-
-        if environ:
-            assert isinstance(environ, dict)
-            self.wsgi_environ.update(environ)
-            if 'on' == environ.get('HTTPS'):
-                self.wsgi_environ['wsgi.url_scheme'] = 'https'
-
-        self.wsgi_curr_headers = None
-        self.wsgi_headers_sent = False
-
-    def wsgi_connection_drop(self, exce, environ=None):
-        """
-        Override this if you're interested in socket exceptions, such
-        as when the user clicks 'Cancel' during a file download.
-        """
-        pass
-
-    def wsgi_execute(self, environ=None):
-        """
-        Invoke the server's ``wsgi_application``.
-        """
-
-        self.wsgi_setup(environ)
-
-        try:
-            result = self.server.wsgi_application(self.wsgi_environ,
-                                                  self.wsgi_start_response)
-            try:
-                for chunk in result:
-                    self.wsgi_write_chunk(chunk)
-                if not self.wsgi_headers_sent:
-                    self.wsgi_write_chunk('')
-            finally:
-                if hasattr(result,'close'):
-                    result.close()
-                result = None
-        except socket.error, exce:
-            self.wsgi_connection_drop(exce, environ)
-            return
-        except:
-            if not self.wsgi_headers_sent:
-                error_msg = "Internal Server Error\n"
-                self.wsgi_curr_headers = (
-                    '500 Internal Server Error',
-                    [('Content-type', 'text/plain'),
-                     ('Content-length', str(len(error_msg)))])
-                self.wsgi_write_chunk("Internal Server Error\n")
-            raise
-
-#
-# SSL Functionality
-#
-# This implementation was motivated by Sebastien Martini's SSL example
-# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/442473
-#
-try:
-    from OpenSSL import SSL, tsafe
-    SocketErrors = (socket.error, SSL.ZeroReturnError, SSL.SysCallError)
-except ImportError:
-    # Do not require pyOpenSSL to be installed, but disable SSL
-    # functionality in that case.
-    SSL = None
-    SocketErrors = (socket.error,)
-    class SecureHTTPServer(HTTPServer):
-        def __init__(self, server_address, RequestHandlerClass,
-                     ssl_context=None, request_queue_size=None):
-            assert not ssl_context, "pyOpenSSL not installed"
-            HTTPServer.__init__(self, server_address, RequestHandlerClass)
-            if request_queue_size:
-                self.socket.listen(request_queue_size)
-else:
-
-    class _ConnFixer(object):
-        """ wraps a socket connection so it implements makefile """
-        def __init__(self, conn):
-            self.__conn = conn
-        def makefile(self, mode, bufsize):
-            return socket._fileobject(self.__conn, mode, bufsize)
-        def __getattr__(self, attrib):
-            return getattr(self.__conn, attrib)
-
-    class SecureHTTPServer(HTTPServer):
-        """
-        Provides SSL server functionality on top of the BaseHTTPServer
-        by overriding _private_ members of Python's standard
-        distribution. The interface for this instance only changes by
-        adding a an optional ssl_context attribute to the constructor:
-
-              cntx = SSL.Context(SSL.SSLv23_METHOD)
-              cntx.use_privatekey_file("host.pem")
-              cntx.use_certificate_file("host.pem")
-
-        """
-
-        def __init__(self, server_address, RequestHandlerClass,
-                     ssl_context=None, request_queue_size=None):
-            # This overrides the implementation of __init__ in python's
-            # SocketServer.TCPServer (which BaseHTTPServer.HTTPServer
-            # does not override, thankfully).
-            HTTPServer.__init__(self, server_address, RequestHandlerClass)
-            self.socket = socket.socket(self.address_family,
-                                        self.socket_type)
-            self.ssl_context = ssl_context
-            if ssl_context:
-                class TSafeConnection(tsafe.Connection):
-                    def settimeout(self, *args):
-                        self._lock.acquire()
-                        try:
-                            return self._ssl_conn.settimeout(*args)
-                        finally:
-                            self._lock.release()
-                self.socket = TSafeConnection(ssl_context, self.socket)
-            self.server_bind()
-            if request_queue_size:
-                self.socket.listen(request_queue_size)
-            self.server_activate()
-
-        def get_request(self):
-            # The default SSL request object does not seem to have a
-            # ``makefile(mode, bufsize)`` method as expected by
-            # Socketserver.StreamRequestHandler.
-            (conn, info) = self.socket.accept()
-            if self.ssl_context:
-                conn = _ConnFixer(conn)
-            return (conn, info)
-
-    def _auto_ssl_context():
-        import OpenSSL, time, random
-        pkey = OpenSSL.crypto.PKey()
-        pkey.generate_key(OpenSSL.crypto.TYPE_RSA, 768)
-
-        cert = OpenSSL.crypto.X509()
-
-        cert.set_serial_number(random.randint(0, sys.maxint))
-        cert.gmtime_adj_notBefore(0)
-        cert.gmtime_adj_notAfter(60 * 60 * 24 * 365)
-        cert.get_subject().CN = '*'
-        cert.get_subject().O = 'Dummy Certificate'
-        cert.get_issuer().CN = 'Untrusted Authority'
-        cert.get_issuer().O = 'Self-Signed'
-        cert.set_pubkey(pkey)
-        cert.sign(pkey, 'md5')
-
-        ctx = SSL.Context(SSL.SSLv23_METHOD)
-        ctx.use_privatekey(pkey)
-        ctx.use_certificate(cert)
-
-        return ctx
-
-class WSGIHandler(WSGIHandlerMixin, BaseHTTPRequestHandler):
-    """
-    A WSGI handler that overrides POST, GET and HEAD to delegate
-    requests to the server's ``wsgi_application``.
-    """
-    server_version = 'PasteWSGIServer/' + __version__
-
-    def handle_one_request(self):
-        """Handle a single HTTP request.
-
-        You normally don't need to override this method; see the class
-        __doc__ string for information on how to handle specific HTTP
-        commands such as GET and POST.
-
-        """
-        self.raw_requestline = self.rfile.readline()
-        if not self.raw_requestline:
-            self.close_connection = 1
-            return
-        if not self.parse_request(): # An error code has been sent, just exit
-            return
-        self.wsgi_execute()
-
-    def handle(self):
-        # don't bother logging disconnects while handling a request
-        try:
-            BaseHTTPRequestHandler.handle(self)
-        except SocketErrors, exce:
-            self.wsgi_connection_drop(exce)
-
-    def address_string(self):
-        """Return the client address formatted for logging.
-
-        This is overridden so that no hostname lookup is done.
-        """
-        return ''
-
-class LimitedLengthFile(object):
-    def __init__(self, file, length):
-        self.file = file
-        self.length = length
-        self._consumed = 0
-        if hasattr(self.file, 'seek'):
-            self.seek = self._seek
-
-    def __repr__(self):
-        base_repr = repr(self.file)
-        return base_repr[:-1] + ' length=%s>' % self.length
-
-    def read(self, length=None):
-        left = self.length - self._consumed
-        if length is None:
-            length = left
-        else:
-            length = min(length, left)
-        # next two lines are hnecessary only if read(0) blocks
-        if not left:
-            return ''
-        data = self.file.read(length)
-        self._consumed += len(data)
-        return data
-
-    def readline(self, *args):
-        max_read = self.length - self._consumed
-        if len(args):
-            max_read = min(args[0], max_read)
-        data = self.file.readline(max_read)
-        self._consumed += len(data)
-        return data
-
-    def readlines(self, hint=None):
-        data = self.file.readlines(hint)
-        for chunk in data:
-            self._consumed += len(chunk)
-        return data
-
-    def __iter__(self):
-        return self
-
-    def next(self):
-        if self.length - self._consumed <= 0:
-            raise StopIteration
-        return self.readline()
-
-    ## Optional methods ##
-
-    def _seek(self, place):
-        self.file.seek(place)
-        self._consumed = place
-
-    def tell(self):
-        if hasattr(self.file, 'tell'):
-            return self.file.tell()
-        else:
-            return self._consumed
-
-class ThreadPool(object):
-    """
-    Generic thread pool with a queue of callables to consume.
-
-    Keeps a notion of the status of its worker threads:
-
-    idle: worker thread with nothing to do
-
-    busy: worker thread doing its job
-
-    hung: worker thread that's been doing a job for too long
-
-    dying: a hung thread that has been killed, but hasn't died quite
-    yet.
-
-    zombie: what was a worker thread that we've tried to kill but
-    isn't dead yet.
-
-    At any time you can call track_threads, to get a dictionary with
-    these keys and lists of thread_ids that fall in that status.  All
-    keys will be present, even if they point to emty lists.
-
-    hung threads are threads that have been busy more than
-    hung_thread_limit seconds.  Hung threads are killed when they live
-    longer than kill_thread_limit seconds.  A thread is then
-    considered dying for dying_limit seconds, if it is still alive
-    after that it is considered a zombie.
-
-    When there are no idle workers and a request comes in, another
-    worker *may* be spawned.  If there are less than spawn_if_under
-    threads in the busy state, another thread will be spawned.  So if
-    the limit is 5, and there are 4 hung threads and 6 busy threads,
-    no thread will be spawned.
-
-    When there are more than max_zombie_threads_before_die zombie
-    threads, a SystemExit exception will be raised, stopping the
-    server.  Use 0 or None to never raise this exception.  Zombie
-    threads *should* get cleaned up, but killing threads is no
-    necessarily reliable.  This is turned off by default, since it is
-    only a good idea if you've deployed the server with some process
-    watching from above (something similar to daemontools or zdaemon).
-
-    Each worker thread only processes ``max_requests`` tasks before it
-    dies and replaces itself with a new worker thread.
-    """
-
-
-    SHUTDOWN = object()
-
-    def __init__(
-        self, nworkers, name="ThreadPool", daemon=False,
-        max_requests=100, # threads are killed after this many requests
-        hung_thread_limit=30, # when a thread is marked "hung"
-        kill_thread_limit=1800, # when you kill that hung thread
-        dying_limit=300, # seconds that a kill should take to go into effect (longer than this and the thread is a "zombie")
-        spawn_if_under=5, # spawn if there's too many hung threads
-        max_zombie_threads_before_die=0, # when to give up on the process
-        hung_check_period=100, # every 100 requests check for hung workers
-        logger=None, # Place to log messages to
-        error_email=None, # Person(s) to notify if serious problem occurs
-        ):
-        """
-        Create thread pool with `nworkers` worker threads.
-        """
-        self.nworkers = nworkers
-        self.max_requests = max_requests
-        self.name = name
-        self.queue = Queue.Queue()
-        self.workers = []
-        self.daemon = daemon
-        if logger is None:
-            logger = logging.getLogger('paste.httpserver.ThreadPool')
-        if isinstance(logger, basestring):
-            logger = logging.getLogger(logger)
-        self.logger = logger
-        self.error_email = error_email
-        self._worker_count = count()
-
-        assert (not kill_thread_limit
-                or kill_thread_limit >= hung_thread_limit), (
-            "kill_thread_limit (%s) should be higher than hung_thread_limit (%s)"
-            % (kill_thread_limit, hung_thread_limit))
-        if not killthread:
-            kill_thread_limit = 0
-            self.logger.info(
-                "Cannot use kill_thread_limit as ctypes/killthread is not available")
-        self.kill_thread_limit = kill_thread_limit
-        self.dying_limit = dying_limit
-        self.hung_thread_limit = hung_thread_limit
-        assert spawn_if_under <= nworkers, (
-            "spawn_if_under (%s) should be less than nworkers (%s)"
-            % (spawn_if_under, nworkers))
-        self.spawn_if_under = spawn_if_under
-        self.max_zombie_threads_before_die = max_zombie_threads_before_die
-        self.hung_check_period = hung_check_period
-        self.requests_since_last_hung_check = 0
-        # Used to keep track of what worker is doing what:
-        self.worker_tracker = {}
-        # Used to keep track of the workers not doing anything:
-        self.idle_workers = []
-        # Used to keep track of threads that have been killed, but maybe aren't dead yet:
-        self.dying_threads = {}
-        # This is used to track when we last had to add idle workers;
-        # we shouldn't cull extra workers until some time has passed
-        # (hung_thread_limit) since workers were added:
-        self._last_added_new_idle_workers = 0
-        if not daemon:
-            atexit.register(self.shutdown)
-        for i in range(self.nworkers):
-            self.add_worker_thread(message='Initial worker pool')
-
-    def add_task(self, task):
-        """
-        Add a task to the queue
-        """
-        self.logger.debug('Added task (%i tasks queued)', self.queue.qsize())
-        if self.hung_check_period:
-            self.requests_since_last_hung_check += 1
-            if self.requests_since_last_hung_check > self.hung_check_period:
-                self.requests_since_last_hung_check = 0
-                self.kill_hung_threads()
-        if not self.idle_workers and self.spawn_if_under:
-            # spawn_if_under can come into effect...
-            busy = 0
-            now = time.time()
-            self.logger.debug('No idle workers for task; checking if we need to make more workers')
-            for worker in self.workers:
-                if not hasattr(worker, 'thread_id'):
-                    # Not initialized
-                    continue
-                time_started, info = self.worker_tracker.get(worker.thread_id,
-                                                             (None, None))
-                if time_started is not None:
-                    if now - time_started < self.hung_thread_limit:
-                        busy += 1
-            if busy < self.spawn_if_under:
-                self.logger.info(
-                    'No idle tasks, and only %s busy tasks; adding %s more '
-                    'workers', busy, self.spawn_if_under-busy)
-                self._last_added_new_idle_workers = time.time()
-                for i in range(self.spawn_if_under - busy):
-                    self.add_worker_thread(message='Response to lack of idle workers')
-            else:
-                self.logger.debug(
-                    'No extra workers needed (%s busy workers)',
-                    busy)
-        if (len(self.workers) > self.nworkers
-            and len(self.idle_workers) > 3
-            and time.time()-self._last_added_new_idle_workers > self.hung_thread_limit):
-            # We've spawned worers in the past, but they aren't needed
-            # anymore; kill off some
-            self.logger.info(
-                'Culling %s extra workers (%s idle workers present)',
-                len(self.workers)-self.nworkers, len(self.idle_workers))
-            self.logger.debug(
-                'Idle workers: %s', self.idle_workers)
-            for i in range(len(self.workers) - self.nworkers):
-                self.queue.put(self.SHUTDOWN)
-        self.queue.put(task)
-
-    def track_threads(self):
-        """
-        Return a dict summarizing the threads in the pool (as
-        described in the ThreadPool docstring).
-        """
-        result = dict(idle=[], busy=[], hung=[], dying=[], zombie=[])
-        now = time.time()
-        for worker in self.workers:
-            if not hasattr(worker, 'thread_id'):
-                # The worker hasn't fully started up, we should just
-                # ignore it
-                continue
-            time_started, info = self.worker_tracker.get(worker.thread_id,
-                                                         (None, None))
-            if time_started is not None:
-                if now - time_started > self.hung_thread_limit:
-                    result['hung'].append(worker)
-                else:
-                    result['busy'].append(worker)
-            else:
-                result['idle'].append(worker)
-        for thread_id, (time_killed, worker) in self.dying_threads.items():
-            if not self.thread_exists(thread_id):
-                # Cull dying threads that are actually dead and gone
-                self.logger.info('Killed thread %s no longer around',
-                                 thread_id)
-                try:
-                    del self.dying_threads[thread_id]
-                except KeyError:
-                    pass
-                continue
-            if now - time_killed > self.dying_limit:
-                result['zombie'].append(worker)
-            else:
-                result['dying'].append(worker)
-        return result
-
-    def kill_worker(self, thread_id):
-        """
-        Removes the worker with the given thread_id from the pool, and
-        replaces it with a new worker thread.
-
-        This should only be done for mis-behaving workers.
-        """
-        if killthread is None:
-            raise RuntimeError(
-                "Cannot kill worker; killthread/ctypes not available")
-        thread_obj = threading._active.get(thread_id)
-        killthread.async_raise(thread_id, SystemExit)
-        try:
-            del self.worker_tracker[thread_id]
-        except KeyError:
-            pass
-        self.logger.info('Killing thread %s', thread_id)
-        if thread_obj in self.workers:
-            self.workers.remove(thread_obj)
-        self.dying_threads[thread_id] = (time.time(), thread_obj)
-        self.add_worker_thread(message='Replacement for killed thread %s' % thread_id)
-
-    def thread_exists(self, thread_id):
-        """
-        Returns true if a thread with this id is still running
-        """
-        return thread_id in threading._active
-
-    def add_worker_thread(self, *args, **kwargs):
-        index = self._worker_count.next()
-        worker = threading.Thread(target=self.worker_thread_callback,
-                                  args=args, kwargs=kwargs,
-                                  name=("worker %d" % index))
-        worker.setDaemon(self.daemon)
-        worker.start()
-
-    def kill_hung_threads(self):
-        """
-        Tries to kill any hung threads
-        """
-        if not self.kill_thread_limit:
-            # No killing should occur
-            return
-        now = time.time()
-        max_time = 0
-        total_time = 0
-        idle_workers = 0
-        starting_workers = 0
-        working_workers = 0
-        killed_workers = 0
-        for worker in self.workers:
-            if not hasattr(worker, 'thread_id'):
-                # Not setup yet
-                starting_workers += 1
-                continue
-            time_started, info = self.worker_tracker.get(worker.thread_id,
-                                                         (None, None))
-            if time_started is None:
-                # Must be idle
-                idle_workers += 1
-                continue
-            working_workers += 1
-            max_time = max(max_time, now-time_started)
-            total_time += now-time_started
-            if now - time_started > self.kill_thread_limit:
-                self.logger.warning(
-                    'Thread %s hung (working on task for %i seconds)',
-                    worker.thread_id, now - time_started)
-                try:
-                    import pprint
-                    info_desc = pprint.pformat(info)
-                except:
-                    out = StringIO()
-                    traceback.print_exc(file=out)
-                    info_desc = 'Error:\n%s' % out.getvalue()
-                self.notify_problem(
-                    "Killing worker thread (id=%(thread_id)s) because it has been \n"
-                    "working on task for %(time)s seconds (limit is %(limit)s)\n"
-                    "Info on task:\n"
-                    "%(info)s"
-                    % dict(thread_id=worker.thread_id,
-                           time=now - time_started,
-                           limit=self.kill_thread_limit,
-                           info=info_desc))
-                self.kill_worker(worker.thread_id)
-                killed_workers += 1
-        if working_workers:
-            ave_time = float(total_time) / working_workers
-            ave_time = '%.2fsec' % ave_time
-        else:
-            ave_time = 'N/A'
-        self.logger.info(
-            "kill_hung_threads status: %s threads (%s working, %s idle, %s starting) "
-            "ave time %s, max time %.2fsec, killed %s workers"
-            % (idle_workers + starting_workers + working_workers,
-               working_workers, idle_workers, starting_workers,
-               ave_time, max_time, killed_workers))
-        self.check_max_zombies()
-
-    def check_max_zombies(self):
-        """
-        Check if we've reached max_zombie_threads_before_die; if so
-        then kill the entire process.
-        """
-        if not self.max_zombie_threads_before_die:
-            return
-        found = []
-        now = time.time()
-        for thread_id, (time_killed, worker) in self.dying_threads.items():
-            if not self.thread_exists(thread_id):
-                # Cull dying threads that are actually dead and gone
-                try:
-                    del self.dying_threads[thread_id]
-                except KeyError:
-                    pass
-                continue
-            if now - time_killed > self.dying_limit:
-                found.append(thread_id)
-        if found:
-            self.logger.info('Found %s zombie threads', found)
-        if len(found) > self.max_zombie_threads_before_die:
-            self.logger.fatal(
-                'Exiting process because %s zombie threads is more than %s limit',
-                len(found), self.max_zombie_threads_before_die)
-            self.notify_problem(
-                "Exiting process because %(found)s zombie threads "
-                "(more than limit of %(limit)s)\n"
-                "Bad threads (ids):\n"
-                "  %(ids)s\n"
-                % dict(found=len(found),
-                       limit=self.max_zombie_threads_before_die,
-                       ids="\n  ".join(map(str, found))),
-                subject="Process restart (too many zombie threads)")
-            self.shutdown(10)
-            print 'Shutting down', threading.currentThread()
-            raise ServerExit(3)
-
-    def worker_thread_callback(self, message=None):
-        """
-        Worker thread should call this method to get and process queued
-        callables.
-        """
-        thread_obj = threading.currentThread()
-        thread_id = thread_obj.thread_id = thread.get_ident()
-        self.workers.append(thread_obj)
-        self.idle_workers.append(thread_id)
-        requests_processed = 0
-        add_replacement_worker = False
-        self.logger.debug('Started new worker %s: %s', thread_id, message)
-        try:
-            while True:
-                if self.max_requests and self.max_requests < requests_processed:
-                    # Replace this thread then die
-                    self.logger.debug('Thread %s processed %i requests (limit %s); stopping thread'
-                                      % (thread_id, requests_processed, self.max_requests))
-                    add_replacement_worker = True
-                    break
-                runnable = self.queue.get()
-                if runnable is ThreadPool.SHUTDOWN:
-                    self.logger.debug('Worker %s asked to SHUTDOWN', thread_id)
-                    break
-                try:
-                    self.idle_workers.remove(thread_id)
-                except ValueError:
-                    pass
-                self.worker_tracker[thread_id] = [time.time(), None]
-                requests_processed += 1
-                try:
-                    try:
-                        runnable()
-                    except:
-                        # We are later going to call sys.exc_clear(),
-                        # removing all remnants of any exception, so
-                        # we should log it now.  But ideally no
-                        # exception should reach this level
-                        print >> sys.stderr, (
-                            'Unexpected exception in worker %r' % runnable)
-                        traceback.print_exc()
-                    if thread_id in self.dying_threads:
-                        # That last exception was intended to kill me
-                        break
-                finally:
-                    try:
-                        del self.worker_tracker[thread_id]
-                    except KeyError:
-                        pass
-                    sys.exc_clear()
-                self.idle_workers.append(thread_id)
-        finally:
-            try:
-                del self.worker_tracker[thread_id]
-            except KeyError:
-                pass
-            try:
-                self.idle_workers.remove(thread_id)
-            except ValueError:
-                pass
-            try:
-                self.workers.remove(thread_obj)
-            except ValueError:
-                pass
-            try:
-                del self.dying_threads[thread_id]
-            except KeyError:
-                pass
-            if add_replacement_worker:
-                self.add_worker_thread(message='Voluntary replacement for thread %s' % thread_id)
-
-    def shutdown(self, force_quit_timeout=0):
-        """
-        Shutdown the queue (after finishing any pending requests).
-        """
-        self.logger.info('Shutting down threadpool')
-        # Add a shutdown request for every worker
-        for i in range(len(self.workers)):
-            self.queue.put(ThreadPool.SHUTDOWN)
-        # Wait for each thread to terminate
-        hung_workers = []
-        for worker in self.workers:
-            worker.join(0.5)
-            if worker.isAlive():
-                hung_workers.append(worker)
-        zombies = []
-        for thread_id in self.dying_threads:
-            if self.thread_exists(thread_id):
-                zombies.append(thread_id)
-        if hung_workers or zombies:
-            self.logger.info("%s workers didn't stop properly, and %s zombies",
-                             len(hung_workers), len(zombies))
-            if hung_workers:
-                for worker in hung_workers:
-                    self.kill_worker(worker.thread_id)
-                self.logger.info('Workers killed forcefully')
-            if force_quit_timeout:
-                hung = []
-                timed_out = False
-                need_force_quit = bool(zombies)
-                for workers in self.workers:
-                    if not timed_out and worker.isAlive():
-                        timed_out = True
-                        worker.join(force_quit_timeout)
-                    if worker.isAlive():
-                        print "Worker %s won't die" % worker
-                        need_force_quit = True
-                if need_force_quit:
-                    import atexit
-                    # Remove the threading atexit callback
-                    for callback in list(atexit._exithandlers):
-                        func = getattr(callback[0], 'im_func', None)
-                        if not func:
-                            continue
-                        globs = getattr(func, 'func_globals', {})
-                        mod = globs.get('__name__')
-                        if mod == 'threading':
-                            atexit._exithandlers.remove(callback)
-                    atexit._run_exitfuncs()
-                    print 'Forcefully exiting process'
-                    os._exit(3)
-                else:
-                    self.logger.info('All workers eventually killed')
-        else:
-            self.logger.info('All workers stopped')
-
-    def notify_problem(self, msg, subject=None, spawn_thread=True):
-        """
-        Called when there's a substantial problem.  msg contains the
-        body of the notification, subject the summary.
-
-        If spawn_thread is true, then the email will be send in
-        another thread (so this doesn't block).
-        """
-        if not self.error_email:
-            return
-        if spawn_thread:
-            t = threading.Thread(
-                target=self.notify_problem,
-                args=(msg, subject, False))
-            t.start()
-            return
-        from_address = 'errors@localhost'
-        if not subject:
-            subject = msg.strip().splitlines()[0]
-            subject = subject[:50]
-            subject = '[http threadpool] %s' % subject
-        headers = [
-            "To: %s" % self.error_email,
-            "From: %s" % from_address,
-            "Subject: %s" % subject,
-            ]
-        try:
-            system = ' '.join(os.uname())
-        except:
-            system = '(unknown)'
-        body = (
-            "An error has occurred in the paste.httpserver.ThreadPool\n"
-            "Error:\n"
-            "  %(msg)s\n"
-            "Occurred at: %(time)s\n"
-            "PID: %(pid)s\n"
-            "System: %(system)s\n"
-            "Server .py file: %(file)s\n"
-            % dict(msg=msg,
-                   time=time.strftime("%c"),
-                   pid=os.getpid(),
-                   system=system,
-                   file=os.path.abspath(__file__),
-                   ))
-        message = '\n'.join(headers) + "\n\n" + body
-        import smtplib
-        server = smtplib.SMTP('localhost')
-        error_emails = [
-            e.strip() for e in self.error_email.split(",")
-            if e.strip()]
-        server.sendmail(from_address, error_emails, message)
-        server.quit()
-        print 'email sent to', error_emails, message
-
-class ThreadPoolMixIn(object):
-    """
-    Mix-in class to process requests from a thread pool
-    """
-    def __init__(self, nworkers, daemon=False, **threadpool_options):
-        # Create and start the workers
-        self.running = True
-        assert nworkers > 0, "ThreadPoolMixIn servers must have at least one worker"
-        self.thread_pool = ThreadPool(
-            nworkers,
-            "ThreadPoolMixIn HTTP server on %s:%d"
-            % (self.server_name, self.server_port),
-            daemon,
-            **threadpool_options)
-
-    def process_request(self, request, client_address):
-        """
-        Queue the request to be processed by on of the thread pool threads
-        """
-        # This sets the socket to blocking mode (and no timeout) since it
-        # may take the thread pool a little while to get back to it. (This
-        # is the default but since we set a timeout on the parent socket so
-        # that we can trap interrupts we need to restore this,.)
-        request.setblocking(1)
-        # Queue processing of the request
-        self.thread_pool.add_task(
-             lambda: self.process_request_in_thread(request, client_address))
-
-    def handle_error(self, request, client_address):
-        exc_class, exc, tb = sys.exc_info()
-        if exc_class is ServerExit:
-            # This is actually a request to stop the server
-            raise
-        return super(ThreadPoolMixIn, self).handle_error(request, client_address)
-
-    def process_request_in_thread(self, request, client_address):
-        """
-        The worker thread should call back here to do the rest of the
-        request processing. Error handling normaller done in 'handle_request'
-        must be done here.
-        """
-        try:
-            self.finish_request(request, client_address)
-            self.close_request(request)
-        except:
-            self.handle_error(request, client_address)
-            self.close_request(request)
-            exc = sys.exc_info()[1]
-            if isinstance(exc, (MemoryError, KeyboardInterrupt)):
-                raise
-
-    def serve_forever(self):
-        """
-        Overrides `serve_forever` to shut the threadpool down cleanly.
-        """
-        try:
-            while self.running:
-                try:
-                    self.handle_request()
-                except socket.timeout:
-                    # Timeout is expected, gives interrupts a chance to
-                    # propogate, just keep handling
-                    pass
-        finally:
-            self.thread_pool.shutdown()
-
-    def server_activate(self):
-        """
-        Overrides server_activate to set timeout on our listener socket.
-        """
-        # We set the timeout here so that we can trap interrupts on windows
-        self.socket.settimeout(1)
-
-    def server_close(self):
-        """
-        Finish pending requests and shutdown the server.
-        """
-        self.running = False
-        self.socket.close()
-        self.thread_pool.shutdown(60)
-
-class WSGIServerBase(SecureHTTPServer):
-    def __init__(self, wsgi_application, server_address,
-                 RequestHandlerClass=None, ssl_context=None,
-                 request_queue_size=None):
-        SecureHTTPServer.__init__(self, server_address,
-                                  RequestHandlerClass, ssl_context,
-                                  request_queue_size=request_queue_size)
-        self.wsgi_application = wsgi_application
-        self.wsgi_socket_timeout = None
-
-    def get_request(self):
-        # If there is a socket_timeout, set it on the accepted
-        (conn,info) = SecureHTTPServer.get_request(self)
-        if self.wsgi_socket_timeout:
-            conn.settimeout(self.wsgi_socket_timeout)
-        return (conn, info)
-
-class WSGIServer(ThreadingMixIn, WSGIServerBase):
-    daemon_threads = False
-
-class WSGIThreadPoolServer(ThreadPoolMixIn, WSGIServerBase):
-    def __init__(self, wsgi_application, server_address,
-                 RequestHandlerClass=None, ssl_context=None,
-                 nworkers=10, daemon_threads=False,
-                 threadpool_options=None, request_queue_size=None):
-        WSGIServerBase.__init__(self, wsgi_application, server_address,
-                                RequestHandlerClass, ssl_context,
-                                request_queue_size=request_queue_size)
-        if threadpool_options is None:
-            threadpool_options = {}
-        ThreadPoolMixIn.__init__(self, nworkers, daemon_threads,
-                                 **threadpool_options)
-
-class ServerExit(SystemExit):
-    """
-    Raised to tell the server to really exit (SystemExit is normally
-    caught)
-    """
-
-def serve(application, host=None, port=None, handler=None, ssl_pem=None,
-          ssl_context=None, server_version=None, protocol_version=None,
-          start_loop=True, daemon_threads=None, socket_timeout=None,
-          use_threadpool=None, threadpool_workers=10,
-          threadpool_options=None, request_queue_size=5):
-    """
-    Serves your ``application`` over HTTP(S) via WSGI interface
-
-    ``host``
-
-        This is the ipaddress to bind to (or a hostname if your
-        nameserver is properly configured).  This defaults to
-        127.0.0.1, which is not a public interface.
-
-    ``port``
-
-        The port to run on, defaults to 8080 for HTTP, or 4443 for
-        HTTPS. This can be a string or an integer value.
-
-    ``handler``
-
-        This is the HTTP request handler to use, it defaults to
-        ``WSGIHandler`` in this module.
-
-    ``ssl_pem``
-
-        This an optional SSL certificate file (via OpenSSL). You can
-        supply ``*`` and a development-only certificate will be
-        created for you, or you can generate a self-signed test PEM
-        certificate file as follows::
-
-            $ openssl genrsa 1024 > host.key
-            $ chmod 400 host.key
-            $ openssl req -new -x509 -nodes -sha1 -days 365  \\
-                          -key host.key > host.cert
-            $ cat host.cert host.key > host.pem
-            $ chmod 400 host.pem
-
-    ``ssl_context``
-
-        This an optional SSL context object for the server.  A SSL
-        context will be automatically constructed for you if you supply
-        ``ssl_pem``.  Supply this to use a context of your own
-        construction.
-
-    ``server_version``
-
-        The version of the server as reported in HTTP response line. This
-        defaults to something like "PasteWSGIServer/0.5".  Many servers
-        hide their code-base identity with a name like 'Amnesiac/1.0'
-
-    ``protocol_version``
-
-        This sets the protocol used by the server, by default
-        ``HTTP/1.0``. There is some support for ``HTTP/1.1``, which
-        defaults to nicer keep-alive connections.  This server supports
-        ``100 Continue``, but does not yet support HTTP/1.1 Chunked
-        Encoding. Hence, if you use HTTP/1.1, you're somewhat in error
-        since chunked coding is a mandatory requirement of a HTTP/1.1
-        server.  If you specify HTTP/1.1, every response *must* have a
-        ``Content-Length`` and you must be careful not to read past the
-        end of the socket.
-
-    ``start_loop``
-
-        This specifies if the server loop (aka ``server.serve_forever()``)
-        should be called; it defaults to ``True``.
-
-    ``daemon_threads``
-
-        This flag specifies if when your webserver terminates all
-        in-progress client connections should be droppped.  It defaults
-        to ``False``.   You might want to set this to ``True`` if you
-        are using ``HTTP/1.1`` and don't set a ``socket_timeout``.
-
-    ``socket_timeout``
-
-        This specifies the maximum amount of time that a connection to a
-        given client will be kept open.  At this time, it is a rude
-        disconnect, but at a later time it might follow the RFC a bit
-        more closely.
-
-    ``use_threadpool``
-
-        Server requests from a pool of worker threads (``threadpool_workers``)
-        rather than creating a new thread for each request. This can
-        substantially reduce latency since there is a high cost associated
-        with thread creation.
-
-    ``threadpool_workers``
-
-        Number of worker threads to create when ``use_threadpool`` is true. This
-        can be a string or an integer value.
-
-    ``threadpool_options``
-
-        A dictionary of options to be used when instantiating the
-        threadpool.  See paste.httpserver.ThreadPool for specific
-        options (``threadpool_workers`` is a specific option that can
-        also go here).
-    
-    ``request_queue_size``
-
-        The 'backlog' argument to socket.listen(); specifies the
-        maximum number of queued connections.
-
-    """
-    is_ssl = False
-    if ssl_pem or ssl_context:
-        assert SSL, "pyOpenSSL is not installed"
-        is_ssl = True
-        port = int(port or 4443)
-        if not ssl_context:
-            if ssl_pem == '*':
-                ssl_context = _auto_ssl_context()
-            else:
-                ssl_context = SSL.Context(SSL.SSLv23_METHOD)
-                ssl_context.use_privatekey_file(ssl_pem)
-                ssl_context.use_certificate_chain_file(ssl_pem)
-
-    host = host or '127.0.0.1'
-    if port is None:
-        if ':' in host:
-            host, port = host.split(':', 1)
-        else:
-            port = 8080
-    server_address = (host, int(port))
-
-    if not handler:
-        handler = WSGIHandler
-    if server_version:
-        handler.server_version = server_version
-        handler.sys_version = None
-    if protocol_version:
-        assert protocol_version in ('HTTP/0.9', 'HTTP/1.0', 'HTTP/1.1')
-        handler.protocol_version = protocol_version
-
-    if use_threadpool is None:
-        use_threadpool = True
-
-    if converters.asbool(use_threadpool):
-        server = WSGIThreadPoolServer(application, server_address, handler,
-                                      ssl_context, int(threadpool_workers),
-                                      daemon_threads,
-                                      threadpool_options=threadpool_options,
-                                      request_queue_size=request_queue_size)
-    else:
-        server = WSGIServer(application, server_address, handler, ssl_context,
-                            request_queue_size=request_queue_size)
-        if daemon_threads:
-            server.daemon_threads = daemon_threads
-
-    if socket_timeout:
-        server.wsgi_socket_timeout = int(socket_timeout)
-
-    if converters.asbool(start_loop):
-        protocol = is_ssl and 'https' or 'http'
-        host, port = server.server_address
-        if host == '0.0.0.0':
-            print 'serving on 0.0.0.0:%s view at %s://127.0.0.1:%s' % \
-                (port, protocol, port)
-        else:
-            print "serving on %s://%s:%s" % (protocol, host, port)
-        try:
-            server.serve_forever()
-        except KeyboardInterrupt:
-            # allow CTRL+C to shutdown
-            pass
-    return server
-
-# For paste.deploy server instantiation (egg:Paste#http)
-# Note: this gets a separate function because it has to expect string
-# arguments (though that's not much of an issue yet, ever?)
-def server_runner(wsgi_app, global_conf, **kwargs):
-    from paste.deploy.converters import asbool
-    for name in ['port', 'socket_timeout', 'threadpool_workers',
-                 'threadpool_hung_thread_limit',
-                 'threadpool_kill_thread_limit',
-                 'threadpool_dying_limit', 'threadpool_spawn_if_under',
-                 'threadpool_max_zombie_threads_before_die',
-                 'threadpool_hung_check_period',
-                 'threadpool_max_requests', 'request_queue_size']:
-        if name in kwargs:
-            kwargs[name] = int(kwargs[name])
-    for name in ['use_threadpool', 'daemon_threads']:
-        if name in kwargs:
-            kwargs[name] = asbool(kwargs[name])
-    threadpool_options = {}
-    for name, value in kwargs.items():
-        if name.startswith('threadpool_') and name != 'threadpool_workers':
-            threadpool_options[name[len('threadpool_'):]] = value
-            del kwargs[name]
-    if ('error_email' not in threadpool_options
-        and 'error_email' in global_conf):
-        threadpool_options['error_email'] = global_conf['error_email']
-    kwargs['threadpool_options'] = threadpool_options
-    serve(wsgi_app, **kwargs)
-
-server_runner.__doc__ = (serve.__doc__ or '') + """
-
-    You can also set these threadpool options:
-
-    ``threadpool_max_requests``:
-
-        The maximum number of requests a worker thread will process
-        before dying (and replacing itself with a new worker thread).
-        Default 100.
-
-    ``threadpool_hung_thread_limit``:
-
-        The number of seconds a thread can work on a task before it is
-        considered hung (stuck).  Default 30 seconds.
-
-    ``threadpool_kill_thread_limit``:
-
-        The number of seconds a thread can work before you should kill it
-        (assuming it will never finish).  Default 600 seconds (10 minutes).
-
-    ``threadpool_dying_limit``:
-
-        The length of time after killing a thread that it should actually
-        disappear.  If it lives longer than this, it is considered a
-        "zombie".  Note that even in easy situations killing a thread can
-        be very slow.  Default 300 seconds (5 minutes).
-
-    ``threadpool_spawn_if_under``:
-
-        If there are no idle threads and a request comes in, and there are
-        less than this number of *busy* threads, then add workers to the
-        pool.  Busy threads are threads that have taken less than
-        ``threadpool_hung_thread_limit`` seconds so far.  So if you get
-        *lots* of requests but they complete in a reasonable amount of time,
-        the requests will simply queue up (adding more threads probably
-        wouldn't speed them up).  But if you have lots of hung threads and
-        one more request comes in, this will add workers to handle it.
-        Default 5.
-
-    ``threadpool_max_zombie_threads_before_die``:
-
-        If there are more zombies than this, just kill the process.  This is
-        only good if you have a monitor that will automatically restart
-        the server.  This can clean up the mess.  Default 0 (disabled).
-
-    `threadpool_hung_check_period``:
-
-        Every X requests, check for hung threads that need to be killed,
-        or for zombie threads that should cause a restart.  Default 100
-        requests.
-
-    ``threadpool_logger``:
-
-        Logging messages will go the logger named here.
-
-    ``threadpool_error_email`` (or global ``error_email`` setting):
-
-        When threads are killed or the process restarted, this email
-        address will be contacted (using an SMTP server on localhost).
-    
-"""
-
-
-if __name__ == '__main__':
-    from paste.wsgilib import dump_environ
-    #serve(dump_environ, ssl_pem="test.pem")
-    serve(dump_environ, server_version="Wombles/1.0",
-          protocol_version="HTTP/1.1", port="8888")
-
diff --git a/lib/paste/lint.py b/lib/paste/lint.py
@@ -1,436 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-# Also licenced under the Apache License, 2.0: http://opensource.org/licenses/apache2.0.php
-# Licensed to PSF under a Contributor Agreement
-"""
-Middleware to check for obedience to the WSGI specification.
-
-Some of the things this checks:
-
-* Signature of the application and start_response (including that
-  keyword arguments are not used).
-
-* Environment checks:
-
-  - Environment is a dictionary (and not a subclass).
-
-  - That all the required keys are in the environment: REQUEST_METHOD,
-    SERVER_NAME, SERVER_PORT, wsgi.version, wsgi.input, wsgi.errors,
-    wsgi.multithread, wsgi.multiprocess, wsgi.run_once
-
-  - That HTTP_CONTENT_TYPE and HTTP_CONTENT_LENGTH are not in the
-    environment (these headers should appear as CONTENT_LENGTH and
-    CONTENT_TYPE).
-
-  - Warns if QUERY_STRING is missing, as the cgi module acts
-    unpredictably in that case.
-
-  - That CGI-style variables (that don't contain a .) have
-    (non-unicode) string values
-
-  - That wsgi.version is a tuple
-
-  - That wsgi.url_scheme is 'http' or 'https' (@@: is this too
-    restrictive?)
-
-  - Warns if the REQUEST_METHOD is not known (@@: probably too
-    restrictive).
-
-  - That SCRIPT_NAME and PATH_INFO are empty or start with /
-
-  - That at least one of SCRIPT_NAME or PATH_INFO are set.
-
-  - That CONTENT_LENGTH is a positive integer.
-
-  - That SCRIPT_NAME is not '/' (it should be '', and PATH_INFO should
-    be '/').
-
-  - That wsgi.input has the methods read, readline, readlines, and
-    __iter__
-
-  - That wsgi.errors has the methods flush, write, writelines
-
-* The status is a string, contains a space, starts with an integer,
-  and that integer is in range (> 100).
-
-* That the headers is a list (not a subclass, not another kind of
-  sequence).
-
-* That the items of the headers are tuples of strings.
-
-* That there is no 'status' header (that is used in CGI, but not in
-  WSGI).
-
-* That the headers don't contain newlines or colons, end in _ or -, or
-  contain characters codes below 037.
-
-* That Content-Type is given if there is content (CGI often has a
-  default content type, but WSGI does not).
-
-* That no Content-Type is given when there is no content (@@: is this
-  too restrictive?)
-
-* That the exc_info argument to start_response is a tuple or None.
-
-* That all calls to the writer are with strings, and no other methods
-  on the writer are accessed.
-
-* That wsgi.input is used properly:
-
-  - .read() is called with zero or one argument
-
-  - That it returns a string
-
-  - That readline, readlines, and __iter__ return strings
-
-  - That .close() is not called
-
-  - No other methods are provided
-
-* That wsgi.errors is used properly:
-
-  - .write() and .writelines() is called with a string
-
-  - That .close() is not called, and no other methods are provided.
-
-* The response iterator:
-
-  - That it is not a string (it should be a list of a single string; a
-    string will work, but perform horribly).
-
-  - That .next() returns a string
-
-  - That the iterator is not iterated over until start_response has
-    been called (that can signal either a server or application
-    error).
-
-  - That .close() is called (doesn't raise exception, only prints to
-    sys.stderr, because we only know it isn't called when the object
-    is garbage collected).
-"""
-
-import re
-import sys
-from types import DictType, StringType, TupleType, ListType
-import warnings
-
-header_re = re.compile(r'^[a-zA-Z][a-zA-Z0-9\-_]*$')
-bad_header_value_re = re.compile(r'[\000-\037]')
-
-class WSGIWarning(Warning):
-    """
-    Raised in response to WSGI-spec-related warnings
-    """
-
-def middleware(application, global_conf=None):
-
-    """
-    When applied between a WSGI server and a WSGI application, this
-    middleware will check for WSGI compliancy on a number of levels.
-    This middleware does not modify the request or response in any
-    way, but will throw an AssertionError if anything seems off
-    (except for a failure to close the application iterator, which
-    will be printed to stderr -- there's no way to throw an exception
-    at that point).
-    """
-    
-    def lint_app(*args, **kw):
-        assert len(args) == 2, "Two arguments required"
-        assert not kw, "No keyword arguments allowed"
-        environ, start_response = args
-
-        check_environ(environ)
-
-        # We use this to check if the application returns without
-        # calling start_response:
-        start_response_started = []
-
-        def start_response_wrapper(*args, **kw):
-            assert len(args) == 2 or len(args) == 3, (
-                "Invalid number of arguments: %s" % args)
-            assert not kw, "No keyword arguments allowed"
-            status = args[0]
-            headers = args[1]
-            if len(args) == 3:
-                exc_info = args[2]
-            else:
-                exc_info = None
-
-            check_status(status)
-            check_headers(headers)
-            check_content_type(status, headers)
-            check_exc_info(exc_info)
-
-            start_response_started.append(None)
-            return WriteWrapper(start_response(*args))
-
-        environ['wsgi.input'] = InputWrapper(environ['wsgi.input'])
-        environ['wsgi.errors'] = ErrorWrapper(environ['wsgi.errors'])
-
-        iterator = application(environ, start_response_wrapper)
-        assert iterator is not None and iterator != False, (
-            "The application must return an iterator, if only an empty list")
-
-        check_iterator(iterator)
-
-        return IteratorWrapper(iterator, start_response_started)
-
-    return lint_app
-
-class InputWrapper(object):
-
-    def __init__(self, wsgi_input):
-        self.input = wsgi_input
-
-    def read(self, *args):
-        assert len(args) <= 1
-        v = self.input.read(*args)
-        assert type(v) is type("")
-        return v
-
-    def readline(self, *args):
-        v = self.input.readline(*args)
-        assert type(v) is type("")
-        return v
-
-    def readlines(self, *args):
-        assert len(args) <= 1
-        lines = self.input.readlines(*args)
-        assert type(lines) is type([])
-        for line in lines:
-            assert type(line) is type("")
-        return lines
-    
-    def __iter__(self):
-        while 1:
-            line = self.readline()
-            if not line:
-                return
-            yield line
-
-    def close(self):
-        assert 0, "input.close() must not be called"
-
-class ErrorWrapper(object):
-
-    def __init__(self, wsgi_errors):
-        self.errors = wsgi_errors
-
-    def write(self, s):
-        assert type(s) is type("")
-        self.errors.write(s)
-
-    def flush(self):
-        self.errors.flush()
-
-    def writelines(self, seq):
-        for line in seq:
-            self.write(line)
-
-    def close(self):
-        assert 0, "errors.close() must not be called"
-
-class WriteWrapper(object):
-
-    def __init__(self, wsgi_writer):
-        self.writer = wsgi_writer
-
-    def __call__(self, s):
-        assert type(s) is type("")
-        self.writer(s)
-
-class PartialIteratorWrapper(object):
-
-    def __init__(self, wsgi_iterator):
-        self.iterator = wsgi_iterator
-
-    def __iter__(self):
-        # We want to make sure __iter__ is called
-        return IteratorWrapper(self.iterator)
-
-class IteratorWrapper(object):
-
-    def __init__(self, wsgi_iterator, check_start_response):
-        self.original_iterator = wsgi_iterator
-        self.iterator = iter(wsgi_iterator)
-        self.closed = False
-        self.check_start_response = check_start_response
-
-    def __iter__(self):
-        return self
-
-    def next(self):
-        assert not self.closed, (
-            "Iterator read after closed")
-        v = self.iterator.next()
-        if self.check_start_response is not None:
-            assert self.check_start_response, (
-                "The application returns and we started iterating over its body, but start_response has not yet been called")
-            self.check_start_response = None
-        return v
-        
-    def close(self):
-        self.closed = True
-        if hasattr(self.original_iterator, 'close'):
-            self.original_iterator.close()
-
-    def __del__(self):
-        if not self.closed:
-            sys.stderr.write(
-                "Iterator garbage collected without being closed")
-        assert self.closed, (
-            "Iterator garbage collected without being closed")
-
-def check_environ(environ):
-    assert type(environ) is DictType, (
-        "Environment is not of the right type: %r (environment: %r)"
-        % (type(environ), environ))
-    
-    for key in ['REQUEST_METHOD', 'SERVER_NAME', 'SERVER_PORT',
-                'wsgi.version', 'wsgi.input', 'wsgi.errors',
-                'wsgi.multithread', 'wsgi.multiprocess',
-                'wsgi.run_once']:
-        assert key in environ, (
-            "Environment missing required key: %r" % key)
-
-    for key in ['HTTP_CONTENT_TYPE', 'HTTP_CONTENT_LENGTH']:
-        assert key not in environ, (
-            "Environment should not have the key: %s "
-            "(use %s instead)" % (key, key[5:]))
-
-    if 'QUERY_STRING' not in environ:
-        warnings.warn(
-            'QUERY_STRING is not in the WSGI environment; the cgi '
-            'module will use sys.argv when this variable is missing, '
-            'so application errors are more likely',
-            WSGIWarning)
-
-    for key in environ.keys():
-        if '.' in key:
-            # Extension, we don't care about its type
-            continue
-        assert type(environ[key]) is StringType, (
-            "Environmental variable %s is not a string: %r (value: %r)"
-            % (key, type(environ[key]), environ[key]))
-        
-    assert type(environ['wsgi.version']) is TupleType, (
-        "wsgi.version should be a tuple (%r)" % environ['wsgi.version'])
-    assert environ['wsgi.url_scheme'] in ('http', 'https'), (
-        "wsgi.url_scheme unknown: %r" % environ['wsgi.url_scheme'])
-
-    check_input(environ['wsgi.input'])
-    check_errors(environ['wsgi.errors'])
-
-    # @@: these need filling out:
-    if environ['REQUEST_METHOD'] not in (
-        'GET', 'HEAD', 'POST', 'OPTIONS','PUT','DELETE','TRACE'):
-        warnings.warn(
-            "Unknown REQUEST_METHOD: %r" % environ['REQUEST_METHOD'],
-            WSGIWarning)
-
-    assert (not environ.get('SCRIPT_NAME')
-            or environ['SCRIPT_NAME'].startswith('/')), (
-        "SCRIPT_NAME doesn't start with /: %r" % environ['SCRIPT_NAME'])
-    assert (not environ.get('PATH_INFO')
-            or environ['PATH_INFO'].startswith('/')), (
-        "PATH_INFO doesn't start with /: %r" % environ['PATH_INFO'])
-    if environ.get('CONTENT_LENGTH'):
-        assert int(environ['CONTENT_LENGTH']) >= 0, (
-            "Invalid CONTENT_LENGTH: %r" % environ['CONTENT_LENGTH'])
-
-    if not environ.get('SCRIPT_NAME'):
-        assert environ.has_key('PATH_INFO'), (
-            "One of SCRIPT_NAME or PATH_INFO are required (PATH_INFO "
-            "should at least be '/' if SCRIPT_NAME is empty)")
-    assert environ.get('SCRIPT_NAME') != '/', (
-        "SCRIPT_NAME cannot be '/'; it should instead be '', and "
-        "PATH_INFO should be '/'")
-
-def check_input(wsgi_input):
-    for attr in ['read', 'readline', 'readlines', '__iter__']:
-        assert hasattr(wsgi_input, attr), (
-            "wsgi.input (%r) doesn't have the attribute %s"
-            % (wsgi_input, attr))
-
-def check_errors(wsgi_errors):
-    for attr in ['flush', 'write', 'writelines']:
-        assert hasattr(wsgi_errors, attr), (
-            "wsgi.errors (%r) doesn't have the attribute %s"
-            % (wsgi_errors, attr))
-
-def check_status(status):
-    assert type(status) is StringType, (
-        "Status must be a string (not %r)" % status)
-    # Implicitly check that we can turn it into an integer:
-    status_code = status.split(None, 1)[0]
-    assert len(status_code) == 3, (
-        "Status codes must be three characters: %r" % status_code)
-    status_int = int(status_code)
-    assert status_int >= 100, "Status code is invalid: %r" % status_int
-    if len(status) < 4 or status[3] != ' ':
-        warnings.warn(
-            "The status string (%r) should be a three-digit integer "
-            "followed by a single space and a status explanation"
-            % status, WSGIWarning)
-
-def check_headers(headers):
-    assert type(headers) is ListType, (
-        "Headers (%r) must be of type list: %r"
-        % (headers, type(headers)))
-    header_names = {}
-    for item in headers:
-        assert type(item) is TupleType, (
-            "Individual headers (%r) must be of type tuple: %r"
-            % (item, type(item)))
-        assert len(item) == 2
-        name, value = item
-        assert name.lower() != 'status', (
-            "The Status header cannot be used; it conflicts with CGI "
-            "script, and HTTP status is not given through headers "
-            "(value: %r)." % value)
-        header_names[name.lower()] = None
-        assert '\n' not in name and ':' not in name, (
-            "Header names may not contain ':' or '\\n': %r" % name)
-        assert header_re.search(name), "Bad header name: %r" % name
-        assert not name.endswith('-') and not name.endswith('_'), (
-            "Names may not end in '-' or '_': %r" % name)
-        assert not bad_header_value_re.search(value), (
-            "Bad header value: %r (bad char: %r)"
-            % (value, bad_header_value_re.search(value).group(0)))
-
-def check_content_type(status, headers):
-    code = int(status.split(None, 1)[0])
-    # @@: need one more person to verify this interpretation of RFC 2616
-    #     http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
-    NO_MESSAGE_BODY = (201, 204, 304)
-    NO_MESSAGE_TYPE = (204, 304)
-    for name, value in headers:
-        if name.lower() == 'content-type':
-            if code not in NO_MESSAGE_TYPE:
-                return
-            assert 0, (("Content-Type header found in a %s response, "
-                        "which must not return content.") % code)
-    if code not in NO_MESSAGE_BODY:
-        assert 0, "No Content-Type header found in headers (%s)" % headers
-
-def check_exc_info(exc_info):
-    assert exc_info is None or type(exc_info) is type(()), (
-        "exc_info (%r) is not a tuple: %r" % (exc_info, type(exc_info)))
-    # More exc_info checks?
-
-def check_iterator(iterator):
-    # Technically a string is legal, which is why it's a really bad
-    # idea, because it may cause the response to be returned
-    # character-by-character
-    assert not isinstance(iterator, str), (
-        "You should not return a string as your application iterator, "
-        "instead return a single-item list containing that string.")
-
-def make_middleware(application, global_conf):
-    # @@: global_conf should be taken out of the middleware function,
-    # and isolated here
-    return middleware(application)
-
-make_middleware.__doc__ = __doc__
-
-__all__ = ['middleware', 'make_middleware']
diff --git a/lib/paste/modpython.py b/lib/paste/modpython.py
@@ -1,252 +0,0 @@
-"""WSGI Paste wrapper for mod_python. Requires Python 2.2 or greater.
-
-
-Example httpd.conf section for a Paste app with an ini file::
-
-    <Location />
-        SetHandler python-program
-        PythonHandler paste.modpython
-        PythonOption paste.ini /some/location/your/pasteconfig.ini
-    </Location>
-    
-Or if you want to load a WSGI application under /your/homedir in the module
-``startup`` and the WSGI app is ``app``::
-
-    <Location />
-        SetHandler python-program
-        PythonHandler paste.modpython
-        PythonPath "['/virtual/project/directory'] + sys.path"
-        PythonOption wsgi.application startup::app
-    </Location>
-
-
-If you'd like to use a virtual installation, make sure to add it in the path
-like so::
-
-    <Location />
-        SetHandler python-program
-        PythonHandler paste.modpython
-        PythonPath "['/virtual/project/directory', '/virtual/lib/python2.4/'] + sys.path"
-        PythonOption paste.ini /virtual/project/directory/pasteconfig.ini
-    </Location>
-
-Some WSGI implementations assume that the SCRIPT_NAME environ variable will
-always be equal to "the root URL of the app"; Apache probably won't act as
-you expect in that case. You can add another PythonOption directive to tell
-modpython_gateway to force that behavior:
-
-    PythonOption SCRIPT_NAME /mcontrol
-
-Some WSGI applications need to be cleaned up when Apache exits. You can
-register a cleanup handler with yet another PythonOption directive:
-
-    PythonOption wsgi.cleanup module::function
-
-The module.function will be called with no arguments on server shutdown,
-once for each child process or thread.
-
-This module highly based on Robert Brewer's, here:
-http://projects.amor.org/misc/svn/modpython_gateway.py
-"""
-
-import traceback
-
-try:
-    from mod_python import apache
-except:
-    pass
-from paste.deploy import loadapp
-
-class InputWrapper(object):
-    
-    def __init__(self, req):
-        self.req = req
-    
-    def close(self):
-        pass
-    
-    def read(self, size=-1):
-        return self.req.read(size)
-    
-    def readline(self, size=-1):
-        return self.req.readline(size)
-    
-    def readlines(self, hint=-1):
-        return self.req.readlines(hint)
-    
-    def __iter__(self):
-        line = self.readline()
-        while line:
-            yield line
-            # Notice this won't prefetch the next line; it only
-            # gets called if the generator is resumed.
-            line = self.readline()
-
-
-class ErrorWrapper(object):
-    
-    def __init__(self, req):
-        self.req = req
-    
-    def flush(self):
-        pass
-    
-    def write(self, msg):
-        self.req.log_error(msg)
-    
-    def writelines(self, seq):
-        self.write(''.join(seq))
-
-
-bad_value = ("You must provide a PythonOption '%s', either 'on' or 'off', "
-             "when running a version of mod_python < 3.1")
-
-
-class Handler(object):
-    
-    def __init__(self, req):
-        self.started = False
-        
-        options = req.get_options()
-        
-        # Threading and forking
-        try:
-            q = apache.mpm_query
-            threaded = q(apache.AP_MPMQ_IS_THREADED)
-            forked = q(apache.AP_MPMQ_IS_FORKED)
-        except AttributeError:
-            threaded = options.get('multithread', '').lower()
-            if threaded == 'on':
-                threaded = True
-            elif threaded == 'off':
-                threaded = False
-            else:
-                raise ValueError(bad_value % "multithread")
-            
-            forked = options.get('multiprocess', '').lower()
-            if forked == 'on':
-                forked = True
-            elif forked == 'off':
-                forked = False
-            else:
-                raise ValueError(bad_value % "multiprocess")
-        
-        env = self.environ = dict(apache.build_cgi_env(req))
-        
-        if 'SCRIPT_NAME' in options:
-            # Override SCRIPT_NAME and PATH_INFO if requested.
-            env['SCRIPT_NAME'] = options['SCRIPT_NAME']
-            env['PATH_INFO'] = req.uri[len(options['SCRIPT_NAME']):]
-        else:
-            env['SCRIPT_NAME'] = ''
-            env['PATH_INFO'] = req.uri
-        
-        env['wsgi.input'] = InputWrapper(req)
-        env['wsgi.errors'] = ErrorWrapper(req)
-        env['wsgi.version'] = (1, 0)
-        env['wsgi.run_once'] = False
-        if env.get("HTTPS") in ('yes', 'on', '1'):
-            env['wsgi.url_scheme'] = 'https'
-        else:
-            env['wsgi.url_scheme'] = 'http'
-        env['wsgi.multithread']  = threaded
-        env['wsgi.multiprocess'] = forked
-        
-        self.request = req
-    
-    def run(self, application):
-        try:
-            result = application(self.environ, self.start_response)
-            for data in result:
-                self.write(data)
-            if not self.started:
-                self.request.set_content_length(0)
-            if hasattr(result, 'close'):
-                result.close()
-        except:
-            traceback.print_exc(None, self.environ['wsgi.errors'])
-            if not self.started:
-                self.request.status = 500
-                self.request.content_type = 'text/plain'
-                data = "A server error occurred. Please contact the administrator."
-                self.request.set_content_length(len(data))
-                self.request.write(data)
-    
-    def start_response(self, status, headers, exc_info=None):
-        if exc_info:
-            try:
-                if self.started:
-                    raise exc_info[0], exc_info[1], exc_info[2]
-            finally:
-                exc_info = None
-        
-        self.request.status = int(status[:3])
-        
-        for key, val in headers:
-            if key.lower() == 'content-length':
-                self.request.set_content_length(int(val))
-            elif key.lower() == 'content-type':
-                self.request.content_type = val
-            else:
-                self.request.headers_out.add(key, val)
-        
-        return self.write
-    
-    def write(self, data):
-        if not self.started:
-            self.started = True
-        self.request.write(data)
-
-
-startup = None
-cleanup = None
-wsgiapps = {}
-
-def handler(req):
-    options = req.get_options()
-    # Run a startup function if requested.
-    global startup
-    if 'wsgi.startup' in options and not startup:
-        func = options['wsgi.startup']
-        if func:
-            module_name, object_str = func.split('::', 1)
-            module = __import__(module_name, globals(), locals(), [''])
-            startup = apache.resolve_object(module, object_str)
-            startup(req)
-    
-    # Register a cleanup function if requested.
-    global cleanup
-    if 'wsgi.cleanup' in options and not cleanup:
-        func = options['wsgi.cleanup']
-        if func:
-            module_name, object_str = func.split('::', 1)
-            module = __import__(module_name, globals(), locals(), [''])
-            cleanup = apache.resolve_object(module, object_str)
-            def cleaner(data):
-                cleanup()
-            try:
-                # apache.register_cleanup wasn't available until 3.1.4.
-                apache.register_cleanup(cleaner)
-            except AttributeError:
-                req.server.register_cleanup(req, cleaner)
-    
-    # Import the wsgi 'application' callable and pass it to Handler.run
-    global wsgiapps
-    appini = options.get('paste.ini')
-    app = None
-    if appini:
-        if appini not in wsgiapps:
-            wsgiapps[appini] = loadapp("config:%s" % appini)
-        app = wsgiapps[appini]
-    
-    # Import the wsgi 'application' callable and pass it to Handler.run
-    appwsgi = options.get('wsgi.application')
-    if appwsgi and not appini:
-        modname, objname = appwsgi.split('::', 1)
-        module = __import__(modname, globals(), locals(), [''])
-        app = getattr(module, objname)
-    
-    Handler(req).run(app)
-    
-    # status was set in Handler; always return apache.OK
-    return apache.OK
diff --git a/lib/paste/pony.py b/lib/paste/pony.py
@@ -1,57 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-We have a pony and/or a unicorn.
-"""
-from paste.request import construct_url
-
-PONY = """
-eJyFkkFuxCAMRfdzCisbJxK2D5D2JpbMrlI3XXQZDt9PCG0ySgcWIMT79rcN0XClUJlZRB9jVmci
-FmV19khjgRFl0RzrKmqzvY8lRUWFlXvCrD7UbAQR/17NUvGhypAF9og16vWtkC8DzUayS6pN3/dR
-ki0OnpzKjUBFpmlC7zVFRNL1rwoq6PWXXQSnIm9WoTzlM2//ke21o5g/l1ckRhiPbkDZXsKIR7l1
-36hF9uMhnRiVjI8UgYjlsIKCrXXpcA9iX5y7zMmtG0fUpW61Ssttipf6cp3WARfkMVoYFryi2a+w
-o/2dhW0OXfcMTnmh53oR9egzPs+qkpY9IKxdUVRP5wHO7UDAuI6moA2N+/z4vtc2k8B+AIBimVU=
-"""
-
-UNICORN = """
-eJyVVD1vhDAM3e9XeAtIxB5P6qlDx0OMXVBzSpZOHdsxP762E0JAnMgZ8Zn37OePAPC60eV1Dl5b
-SS7fB6DmQNGhtegpNlPIQS8HmkYGdSqNqDF9wcMYus4TuBYGsZwIPqXfEoNir5K+R3mbzhlR4JMW
-eGpikPpn9wHl2sDgEH1270guZwzKDRf3nTztMvfI5r3fJqEmNxdCyISBcWjNgjPG8Egg2hgT3mJi
-KBwNvmPB1hbWJ3TwBfMlqdTzxNyDE2H8zOD5HA4KkqJGPVY/TwnxmPA82kdSJNj7zs+R0d1pB+JO
-xn2DKgsdxAfFS2pfTSD0Fb6Uzv7dCQSvE5JmZQEQ90vNjBU1GPuGQpCPS8cGo+dQgjIKqxnJTXbw
-ucFzPFVIJXtzk6BXKGPnYsKzvFmGx7A0j6Zqvlvk5rETXbMWTGWj0RFc8QNPYVfhJfMMniCPazWJ
-lGtPZecIGJWW6oL2hpbWRZEkChe8eg5Wb7xx/MBZBFjxeZPEss+mRQ3Uhc8WQv684seSRO7i3nb4
-7HlKUg8sraz47LmXyh8S0somADvoUpoHjGWl+rUkF0H+EIf/gbyyMg58BBk6L634/fkHUCodMw==
-"""
-
-
-class PonyMiddleware(object):
-
-    def __init__(self, application):
-        self.application = application
-
-    def __call__(self, environ, start_response):
-        path_info = environ.get('PATH_INFO', '')
-        if path_info == '/pony':
-            url = construct_url(environ, with_query_string=False)
-            if 'horn' in environ.get('QUERY_STRING', ''):
-                data = UNICORN
-                link = 'remove horn!'
-            else:
-                data = PONY
-                url += '?horn'
-                link = 'add horn!'
-            msg = data.decode('base64').decode('zlib')
-            msg = '<pre>%s\n<a href="%s">%s</a></pre>' % (
-                msg, url, link)
-            start_response('200 OK', [('content-type', 'text/html')])
-            return [msg]
-        else:
-            return self.application(environ, start_response)
-
-def make_pony(app, global_conf):
-    """
-    Adds pony power to any application, at /pony
-    """
-    return PonyMiddleware(app)
-
diff --git a/lib/paste/progress.py b/lib/paste/progress.py
@@ -1,222 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-# (c) 2005 Clark C. Evans
-# This module is part of the Python Paste Project and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-# This code was written with funding by http://prometheusresearch.com
-"""
-Upload Progress Monitor
-
-This is a WSGI middleware component which monitors the status of files
-being uploaded.  It includes a small query application which will return
-a list of all files being uploaded by particular session/user.
-
->>> from paste.httpserver import serve
->>> from paste.urlmap import URLMap
->>> from paste.auth.basic import AuthBasicHandler
->>> from paste.debug.debugapp import SlowConsumer, SimpleApplication
->>> # from paste.progress import *
->>> realm = 'Test Realm'
->>> def authfunc(username, password):
-...     return username == password
->>> map = URLMap({})
->>> ups = UploadProgressMonitor(map, threshold=1024)
->>> map['/upload'] = SlowConsumer()
->>> map['/simple'] = SimpleApplication()
->>> map['/report'] = UploadProgressReporter(ups)
->>> serve(AuthBasicHandler(ups, realm, authfunc))
-serving on...
-
-.. note::
-
-   This is experimental, and will change in the future.
-"""
-import time
-from paste.wsgilib import catch_errors
-
-DEFAULT_THRESHOLD = 1024 * 1024  # one megabyte
-DEFAULT_TIMEOUT   = 60*5         # five minutes
-ENVIRON_RECEIVED  = 'paste.bytes_received'
-REQUEST_STARTED   = 'paste.request_started'
-REQUEST_FINISHED  = 'paste.request_finished'
-
-class _ProgressFile(object):
-    """
-    This is the input-file wrapper used to record the number of
-    ``paste.bytes_received`` for the given request.
-    """
-
-    def __init__(self, environ, rfile):
-        self._ProgressFile_environ = environ
-        self._ProgressFile_rfile   = rfile
-        self.flush = rfile.flush
-        self.write = rfile.write
-        self.writelines = rfile.writelines
-
-    def __iter__(self):
-        environ = self._ProgressFile_environ
-        riter = iter(self._ProgressFile_rfile)
-        def iterwrap():
-            for chunk in riter:
-                environ[ENVIRON_RECEIVED] += len(chunk)
-                yield chunk
-        return iter(iterwrap)
-
-    def read(self, size=-1):
-        chunk = self._ProgressFile_rfile.read(size)
-        self._ProgressFile_environ[ENVIRON_RECEIVED] += len(chunk)
-        return chunk
-
-    def readline(self):
-        chunk = self._ProgressFile_rfile.readline()
-        self._ProgressFile_environ[ENVIRON_RECEIVED] += len(chunk)
-        return chunk
-
-    def readlines(self, hint=None):
-        chunk = self._ProgressFile_rfile.readlines(hint)
-        self._ProgressFile_environ[ENVIRON_RECEIVED] += len(chunk)
-        return chunk
-
-class UploadProgressMonitor(object):
-    """
-    monitors and reports on the status of uploads in progress
-
-    Parameters:
-
-        ``application``
-
-            This is the next application in the WSGI stack.
-
-        ``threshold``
-
-            This is the size in bytes that is needed for the
-            upload to be included in the monitor.
-
-        ``timeout``
-
-            This is the amount of time (in seconds) that a upload
-            remains in the monitor after it has finished.
-
-    Methods:
-
-        ``uploads()``
-
-            This returns a list of ``environ`` dict objects for each
-            upload being currently monitored, or finished but whose time
-            has not yet expired.
-
-    For each request ``environ`` that is monitored, there are several
-    variables that are stored:
-
-        ``paste.bytes_received``
-
-            This is the total number of bytes received for the given
-            request; it can be compared with ``CONTENT_LENGTH`` to
-            build a percentage complete.  This is an integer value.
-
-        ``paste.request_started``
-
-            This is the time (in seconds) when the request was started
-            as obtained from ``time.time()``.  One would want to format
-            this for presentation to the user, if necessary.
-
-        ``paste.request_finished``
-
-            This is the time (in seconds) when the request was finished,
-            canceled, or otherwise disconnected.  This is None while
-            the given upload is still in-progress.
-
-    TODO: turn monitor into a queue and purge queue of finished
-          requests that have passed the timeout period.
-    """
-    def __init__(self, application, threshold=None, timeout=None):
-        self.application = application
-        self.threshold = threshold or DEFAULT_THRESHOLD
-        self.timeout   = timeout   or DEFAULT_TIMEOUT
-        self.monitor   = []
-
-    def __call__(self, environ, start_response):
-        length = environ.get('CONTENT_LENGTH', 0)
-        if length and int(length) > self.threshold:
-            # replace input file object
-            self.monitor.append(environ)
-            environ[ENVIRON_RECEIVED] = 0
-            environ[REQUEST_STARTED] = time.time()
-            environ[REQUEST_FINISHED] = None
-            environ['wsgi.input'] = \
-                _ProgressFile(environ, environ['wsgi.input'])
-            def finalizer(exc_info=None):
-                environ[REQUEST_FINISHED] = time.time()
-            return catch_errors(self.application, environ,
-                       start_response, finalizer, finalizer)
-        return self.application(environ, start_response)
-
-    def uploads(self):
-        return self.monitor
-
-class UploadProgressReporter(object):
-    """
-    reports on the progress of uploads for a given user
-
-    This reporter returns a JSON file (for use in AJAX) listing the
-    uploads in progress for the given user.  By default, this reporter
-    uses the ``REMOTE_USER`` environment to compare between the current
-    request and uploads in-progress.  If they match, then a response
-    record is formed.
-
-        ``match()``
-
-            This member function can be overriden to provide alternative
-            matching criteria.  It takes two environments, the first
-            is the current request, the second is a current upload.
-
-        ``report()``
-
-            This member function takes an environment and builds a
-            ``dict`` that will be used to create a JSON mapping for
-            the given upload.  By default, this just includes the
-            percent complete and the request url.
-
-    """
-    def __init__(self, monitor):
-        self.monitor   = monitor
-
-    def match(self, search_environ, upload_environ):
-        if search_environ.get('REMOTE_USER', None) == \
-           upload_environ.get('REMOTE_USER', 0):
-            return True
-        return False
-
-    def report(self, environ):
-        retval = { 'started': time.strftime("%Y-%m-%d %H:%M:%S",
-                                time.gmtime(environ[REQUEST_STARTED])),
-                   'finished': '',
-                   'content_length': environ.get('CONTENT_LENGTH'),
-                   'bytes_received': environ[ENVIRON_RECEIVED],
-                   'path_info': environ.get('PATH_INFO',''),
-                   'query_string': environ.get('QUERY_STRING','')}
-        finished = environ[REQUEST_FINISHED]
-        if finished:
-            retval['finished'] = time.strftime("%Y:%m:%d %H:%M:%S",
-                                               time.gmtime(finished))
-        return retval
-
-    def __call__(self, environ, start_response):
-        body = []
-        for map in [self.report(env) for env in self.monitor.uploads()
-                                             if self.match(environ, env)]:
-            parts = []
-            for k, v in map.items():
-                v = str(v).replace("\\", "\\\\").replace('"', '\\"')
-                parts.append('%s: "%s"' % (k, v))
-            body.append("{ %s }" % ", ".join(parts))
-        body = "[ %s ]" % ", ".join(body)
-        start_response("200 OK", [('Content-Type', 'text/plain'),
-                                  ('Content-Length', len(body))])
-        return [body]
-
-__all__ = ['UploadProgressMonitor', 'UploadProgressReporter']
-
-if "__main__" == __name__:
-    import doctest
-    doctest.testmod(optionflags=doctest.ELLIPSIS)
diff --git a/lib/paste/proxy.py b/lib/paste/proxy.py
@@ -1,276 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-An application that proxies WSGI requests to a remote server.
-
-TODO:
-
-* Send ``Via`` header?  It's not clear to me this is a Via in the
-  style of a typical proxy.
-
-* Other headers or metadata?  I put in X-Forwarded-For, but that's it.
-
-* Signed data of non-HTTP keys?  This would be for things like
-  REMOTE_USER.
-
-* Something to indicate what the original URL was?  The original host,
-  scheme, and base path.
-
-* Rewriting ``Location`` headers?  mod_proxy does this.
-
-* Rewriting body?  (Probably not on this one -- that can be done with
-  a different middleware that wraps this middleware)
-
-* Example::  
-    
-    use = egg:Paste#proxy
-    address = http://server3:8680/exist/rest/db/orgs/sch/config/
-    allowed_request_methods = GET
-  
-"""
-
-import httplib
-import urlparse
-import urllib
-
-from paste import httpexceptions
-from paste.util.converters import aslist
-
-# Remove these headers from response (specify lower case header
-# names):
-filtered_headers = (     
-    'transfer-encoding',
-    'connection',
-    'keep-alive',
-    'proxy-authenticate',
-    'proxy-authorization',
-    'te',
-    'trailers',
-    'upgrade',
-)
-
-class Proxy(object):
-
-    def __init__(self, address, allowed_request_methods=(),
-                 suppress_http_headers=()):
-        self.address = address
-        self.parsed = urlparse.urlsplit(address)
-        self.scheme = self.parsed[0].lower()
-        self.host = self.parsed[1]
-        self.path = self.parsed[2]
-        self.allowed_request_methods = [
-            x.lower() for x in allowed_request_methods if x]
-        
-        self.suppress_http_headers = [
-            x.lower() for x in suppress_http_headers if x]
-
-    def __call__(self, environ, start_response):
-        if (self.allowed_request_methods and 
-            environ['REQUEST_METHOD'].lower() not in self.allowed_request_methods):
-            return httpexceptions.HTTPBadRequest("Disallowed")(environ, start_response)
-
-        if self.scheme == 'http':
-            ConnClass = httplib.HTTPConnection
-        elif self.scheme == 'https':
-            ConnClass = httplib.HTTPSConnection
-        else:
-            raise ValueError(
-                "Unknown scheme for %r: %r" % (self.address, self.scheme))
-        conn = ConnClass(self.host)
-        headers = {}
-        for key, value in environ.items():
-            if key.startswith('HTTP_'):
-                key = key[5:].lower().replace('_', '-')
-                if key == 'host' or key in self.suppress_http_headers:
-                    continue
-                headers[key] = value
-        headers['host'] = self.host
-        if 'REMOTE_ADDR' in environ:
-            headers['x-forwarded-for'] = environ['REMOTE_ADDR']
-        if environ.get('CONTENT_TYPE'):
-            headers['content-type'] = environ['CONTENT_TYPE']
-        if environ.get('CONTENT_LENGTH'):
-            headers['content-length'] = environ['CONTENT_LENGTH'] 
-            length = int(environ['CONTENT_LENGTH'])
-            body = environ['wsgi.input'].read(length)
-        else:
-            body = ''
-            
-        path_info = urllib.quote(environ['PATH_INFO'])
-        if self.path:            
-            request_path = path_info
-            if request_path[0] == '/':
-                request_path = request_path[1:]
-                
-            path = urlparse.urljoin(self.path, request_path)
-        else:
-            path = path_info
-        if environ.get('QUERY_STRING'):
-            path += '?' + environ['QUERY_STRING']
-            
-        conn.request(environ['REQUEST_METHOD'],
-                     path,
-                     body, headers)
-        res = conn.getresponse()
-        headers_out = parse_headers(res.msg)
-        
-        status = '%s %s' % (res.status, res.reason)
-        start_response(status, headers_out)
-        # @@: Default?
-        length = res.getheader('content-length')
-        if length is not None:
-            body = res.read(int(length))
-        else:
-            body = res.read()
-        conn.close()
-        return [body]
-
-def make_proxy(global_conf, address, allowed_request_methods="",
-               suppress_http_headers=""):
-    """
-    Make a WSGI application that proxies to another address:
-    
-    ``address``
-        the full URL ending with a trailing ``/``
-        
-    ``allowed_request_methods``:
-        a space seperated list of request methods (e.g., ``GET POST``)
-        
-    ``suppress_http_headers``
-        a space seperated list of http headers (lower case, without
-        the leading ``http_``) that should not be passed on to target
-        host
-    """
-    allowed_request_methods = aslist(allowed_request_methods)
-    suppress_http_headers = aslist(suppress_http_headers)
-    return Proxy(
-        address,
-        allowed_request_methods=allowed_request_methods,
-        suppress_http_headers=suppress_http_headers)
-
-
-class TransparentProxy(object):
-
-    """
-    A proxy that sends the request just as it was given, including
-    respecting HTTP_HOST, wsgi.url_scheme, etc.
-
-    This is a way of translating WSGI requests directly to real HTTP
-    requests.  All information goes in the environment; modify it to
-    modify the way the request is made.
-
-    If you specify ``force_host`` (and optionally ``force_scheme``)
-    then HTTP_HOST won't be used to determine where to connect to;
-    instead a specific host will be connected to, but the ``Host``
-    header in the request will remain intact.
-    """
-
-    def __init__(self, force_host=None,
-                 force_scheme='http'):
-        self.force_host = force_host
-        self.force_scheme = force_scheme
-
-    def __repr__(self):
-        return '<%s %s force_host=%r force_scheme=%r>' % (
-            self.__class__.__name__,
-            hex(id(self)),
-            self.force_host, self.force_scheme)
-
-    def __call__(self, environ, start_response):
-        scheme = environ['wsgi.url_scheme']
-        if self.force_host is None:
-            conn_scheme = scheme
-        else:
-            conn_scheme = self.force_scheme
-        if conn_scheme == 'http':
-            ConnClass = httplib.HTTPConnection
-        elif conn_scheme == 'https':
-            ConnClass = httplib.HTTPSConnection
-        else:
-            raise ValueError(
-                "Unknown scheme %r" % scheme)
-        if 'HTTP_HOST' not in environ:
-            raise ValueError(
-                "WSGI environ must contain an HTTP_HOST key")
-        host = environ['HTTP_HOST']
-        if self.force_host is None:
-            conn_host = host
-        else:
-            conn_host = self.force_host
-        conn = ConnClass(conn_host)
-        headers = {}
-        for key, value in environ.items():
-            if key.startswith('HTTP_'):
-                key = key[5:].lower().replace('_', '-')
-                headers[key] = value
-        headers['host'] = host
-        if 'REMOTE_ADDR' in environ and 'HTTP_X_FORWARDED_FOR' not in environ:
-            headers['x-forwarded-for'] = environ['REMOTE_ADDR']
-        if environ.get('CONTENT_TYPE'):
-            headers['content-type'] = environ['CONTENT_TYPE']
-        if environ.get('CONTENT_LENGTH'):
-            length = int(environ['CONTENT_LENGTH'])
-            body = environ['wsgi.input'].read(length)
-        elif 'CONTENT_LENGTH' not in environ:
-            body = ''
-            length = 0
-        else:
-            body = ''
-            length = 0
-        
-        path = (environ.get('SCRIPT_NAME', '')
-                + environ.get('PATH_INFO', ''))
-        path = urllib.quote(path)
-        if 'QUERY_STRING' in environ:
-            path += '?' + environ['QUERY_STRING']
-        conn.request(environ['REQUEST_METHOD'],
-                     path, body, headers)
-        res = conn.getresponse()
-        headers_out = parse_headers(res.msg)
-                
-        status = '%s %s' % (res.status, res.reason)
-        start_response(status, headers_out)
-        # @@: Default?
-        length = res.getheader('content-length')
-        if length is not None:
-            body = res.read(int(length))
-        else:
-            body = res.read()
-        conn.close()
-        return [body]
-
-def parse_headers(message):
-    """
-    Turn a Message object into a list of WSGI-style headers.
-    """
-    headers_out = []        
-    for full_header in message.headers:
-        if not full_header:            
-            # Shouldn't happen, but we'll just ignore
-            continue                     
-        if full_header[0].isspace():
-            # Continuation line, add to the last header
-            if not headers_out:                        
-                raise ValueError(
-                    "First header starts with a space (%r)" % full_header)
-            last_header, last_value = headers_out.pop()                   
-            value = last_value + ' ' + full_header.strip()
-            headers_out.append((last_header, value))      
-            continue                                
-        try:        
-            header, value = full_header.split(':', 1)
-        except:                                      
-            raise ValueError("Invalid header: %r" % full_header)
-        value = value.strip()                                   
-        if header.lower() not in filtered_headers:
-            headers_out.append((header, value))   
-    return headers_out
-
-def make_transparent_proxy(
-    global_conf, force_host=None, force_scheme='http'):
-    """
-    Create a proxy that connects to a specific host, but does
-    absolutely no other filtering, including the Host header.
-    """
-    return TransparentProxy(force_host=force_host,
-                            force_scheme=force_scheme)
diff --git a/lib/paste/recursive.py b/lib/paste/recursive.py
@@ -1,401 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-Middleware to make internal requests and forward requests internally.
-
-When applied, several keys are added to the environment that will allow
-you to trigger recursive redirects and forwards.
-
-  paste.recursive.include:
-      When you call
-      ``environ['paste.recursive.include'](new_path_info)`` a response
-      will be returned.  The response has a ``body`` attribute, a
-      ``status`` attribute, and a ``headers`` attribute.
-
-  paste.recursive.script_name:
-      The ``SCRIPT_NAME`` at the point that recursive lives.  Only
-      paths underneath this path can be redirected to.
-
-  paste.recursive.old_path_info:
-      A list of previous ``PATH_INFO`` values from previous redirects.
-
-Raise ``ForwardRequestException(new_path_info)`` to do a forward
-(aborting the current request).
-"""
-
-from cStringIO import StringIO
-import warnings
-
-__all__ = ['RecursiveMiddleware']
-__pudge_all__ =  ['RecursiveMiddleware', 'ForwardRequestException']
-
-class CheckForRecursionMiddleware(object):
-    def __init__(self, app, env):
-        self.app = app
-        self.env = env
-        
-    def __call__(self, environ, start_response):
-        path_info = environ.get('PATH_INFO','')
-        if path_info in self.env.get(
-            'paste.recursive.old_path_info', []):
-            raise AssertionError(
-                "Forwarding loop detected; %r visited twice (internal "
-                "redirect path: %s)"
-                % (path_info, self.env['paste.recursive.old_path_info']))
-        old_path_info = self.env.setdefault('paste.recursive.old_path_info', [])
-        old_path_info.append(self.env.get('PATH_INFO', ''))
-        return self.app(environ, start_response)
-
-class RecursiveMiddleware(object):
-
-    """
-    A WSGI middleware that allows for recursive and forwarded calls.
-    All these calls go to the same 'application', but presumably that
-    application acts differently with different URLs.  The forwarded
-    URLs must be relative to this container.
-
-    Interface is entirely through the ``paste.recursive.forward`` and
-    ``paste.recursive.include`` environmental keys.
-    """
-
-    def __init__(self, application, global_conf=None):
-        self.application = application
-
-    def __call__(self, environ, start_response):
-        environ['paste.recursive.forward'] = Forwarder(
-            self.application, 
-            environ, 
-            start_response)
-        environ['paste.recursive.include'] = Includer(
-            self.application, 
-            environ, 
-            start_response)
-        environ['paste.recursive.include_app_iter'] = IncluderAppIter(
-            self.application,
-            environ,
-            start_response)
-        my_script_name = environ.get('SCRIPT_NAME', '')
-        environ['paste.recursive.script_name'] = my_script_name
-        try:
-            return self.application(environ, start_response)
-        except ForwardRequestException, e:
-            middleware = CheckForRecursionMiddleware(
-                e.factory(self), environ)
-            return middleware(environ, start_response)
-
-class ForwardRequestException(Exception):
-    """
-    Used to signal that a request should be forwarded to a different location.
-    
-    ``url``
-        The URL to forward to starting with a ``/`` and relative to 
-        ``RecursiveMiddleware``. URL fragments can also contain query strings 
-        so ``/error?code=404`` would be a valid URL fragment.
-    
-    ``environ``
-        An altertative WSGI environment dictionary to use for the forwarded 
-        request. If specified is used *instead* of the ``url_fragment``
-     
-    ``factory``
-        If specifed ``factory`` is used instead of ``url`` or ``environ``. 
-        ``factory`` is a callable that takes a WSGI application object 
-        as the first argument and returns an initialised WSGI middleware
-        which can alter the forwarded response.
-
-    Basic usage (must have ``RecursiveMiddleware`` present) :
-    
-    .. code-block:: python
-    
-        from paste.recursive import ForwardRequestException
-        def app(environ, start_response):
-            if environ['PATH_INFO'] == '/hello':
-                start_response("200 OK", [('Content-type', 'text/plain')])
-                return ['Hello World!']
-            elif environ['PATH_INFO'] == '/error':
-                start_response("404 Not Found", [('Content-type', 'text/plain')])
-                return ['Page not found']
-            else:
-                raise ForwardRequestException('/error')
-                
-        from paste.recursive import RecursiveMiddleware
-        app = RecursiveMiddleware(app)
-        
-    If you ran this application and visited ``/hello`` you would get a 
-    ``Hello World!`` message. If you ran the application and visited 
-    ``/not_found`` a ``ForwardRequestException`` would be raised and the caught
-    by the ``RecursiveMiddleware``. The ``RecursiveMiddleware`` would then 
-    return the headers and response from the ``/error`` URL but would display 
-    a ``404 Not found`` status message.
-    
-    You could also specify an ``environ`` dictionary instead of a url. Using 
-    the same example as before:
-    
-    .. code-block:: python
-    
-        def app(environ, start_response):
-            ... same as previous example ...
-            else:
-                new_environ = environ.copy()
-                new_environ['PATH_INFO'] = '/error'
-                raise ForwardRequestException(environ=new_environ)
-                
-    Finally, if you want complete control over every aspect of the forward you
-    can specify a middleware factory. For example to keep the old status code 
-    but use the headers and resposne body from the forwarded response you might
-    do this:
-    
-    .. code-block:: python
-
-        from paste.recursive import ForwardRequestException
-        from paste.recursive import RecursiveMiddleware
-        from paste.errordocument import StatusKeeper
-
-        def app(environ, start_response):
-            if environ['PATH_INFO'] == '/hello':
-                start_response("200 OK", [('Content-type', 'text/plain')])
-                return ['Hello World!']
-            elif environ['PATH_INFO'] == '/error':
-                start_response("404 Not Found", [('Content-type', 'text/plain')])
-                return ['Page not found']
-            else:
-                def factory(app):
-                    return StatusKeeper(app, status='404 Not Found', url='/error')
-                raise ForwardRequestException(factory=factory)
-
-        app = RecursiveMiddleware(app)
-    """
-
-    def __init__(
-        self, 
-        url=None, 
-        environ={}, 
-        factory=None, 
-        path_info=None):
-        # Check no incompatible options have been chosen
-        if factory and url:
-            raise TypeError(
-                'You cannot specify factory and a url in '
-                'ForwardRequestException')
-        elif factory and environ:
-            raise TypeError(
-                'You cannot specify factory and environ in '
-                'ForwardRequestException')
-        if url and environ:
-            raise TypeError(
-                'You cannot specify environ and url in '
-                'ForwardRequestException')
-
-        # set the path_info or warn about its use.
-        if path_info:
-            if not url:
-                warnings.warn(
-                    "ForwardRequestException(path_info=...) has been deprecated; please "
-                    "use ForwardRequestException(url=...)",
-                    DeprecationWarning, 2)
-            else:
-                raise TypeError('You cannot use url and path_info in ForwardRequestException')
-            self.path_info = path_info
-    
-        # If the url can be treated as a path_info do that
-        if url and not '?' in str(url): 
-            self.path_info = url
-            
-        # Base middleware
-        class ForwardRequestExceptionMiddleware(object):
-            def __init__(self, app):
-                self.app = app
-                            
-        # Otherwise construct the appropriate middleware factory
-        if hasattr(self, 'path_info'):
-            p = self.path_info
-            def factory_(app):
-                class PathInfoForward(ForwardRequestExceptionMiddleware):
-                    def __call__(self, environ, start_response):
-                        environ['PATH_INFO'] = p
-                        return self.app(environ, start_response)
-                return PathInfoForward(app)
-            self.factory = factory_
-        elif url:
-            def factory_(app):
-                class URLForward(ForwardRequestExceptionMiddleware):
-                    def __call__(self, environ, start_response):
-                        environ['PATH_INFO'] = url.split('?')[0]
-                        environ['QUERY_STRING'] = url.split('?')[1]
-                        return self.app(environ, start_response)
-                return URLForward(app)
-            self.factory = factory_
-        elif environ:
-            def factory_(app):
-                class EnvironForward(ForwardRequestExceptionMiddleware):
-                    def __call__(self, environ_, start_response):
-                        return self.app(environ, start_response)
-                return EnvironForward(app)
-            self.factory = factory_
-        else:
-            self.factory = factory
-
-class Recursive(object):
-
-    def __init__(self, application, environ, start_response):
-        self.application = application
-        self.original_environ = environ.copy()
-        self.previous_environ = environ
-        self.start_response = start_response
-
-    def __call__(self, path, extra_environ=None):
-        """
-        `extra_environ` is an optional dictionary that is also added
-        to the forwarded request.  E.g., ``{'HTTP_HOST': 'new.host'}``
-        could be used to forward to a different virtual host.
-        """
-        environ = self.original_environ.copy()
-        if extra_environ:
-            environ.update(extra_environ)
-        environ['paste.recursive.previous_environ'] = self.previous_environ
-        base_path = self.original_environ.get('SCRIPT_NAME')
-        if path.startswith('/'):
-            assert path.startswith(base_path), (
-                "You can only forward requests to resources under the "
-                "path %r (not %r)" % (base_path, path))
-            path = path[len(base_path)+1:]
-        assert not path.startswith('/')
-        path_info = '/' + path
-        environ['PATH_INFO'] = path_info
-        environ['REQUEST_METHOD'] = 'GET'
-        environ['CONTENT_LENGTH'] = '0'
-        environ['CONTENT_TYPE'] = ''
-        environ['wsgi.input'] = StringIO('')
-        return self.activate(environ)
-
-    def activate(self, environ):
-        raise NotImplementedError
-
-    def __repr__(self):
-        return '<%s.%s from %s>' % (
-            self.__class__.__module__,
-            self.__class__.__name__,
-            self.original_environ.get('SCRIPT_NAME') or '/')
-
-class Forwarder(Recursive):
-
-    """
-    The forwarder will try to restart the request, except with
-    the new `path` (replacing ``PATH_INFO`` in the request).
-
-    It must not be called after and headers have been returned.
-    It returns an iterator that must be returned back up the call
-    stack, so it must be used like:
-    
-    .. code-block:: python
-
-        return environ['paste.recursive.forward'](path)
-
-    Meaningful transformations cannot be done, since headers are
-    sent directly to the server and cannot be inspected or
-    rewritten.
-    """
-
-    def activate(self, environ):
-        warnings.warn(
-            "recursive.Forwarder has been deprecated; please use "
-            "ForwardRequestException",
-            DeprecationWarning, 2)
-        return self.application(environ, self.start_response)
-    
-
-class Includer(Recursive):
-
-    """
-    Starts another request with the given path and adding or
-    overwriting any values in the `extra_environ` dictionary.
-    Returns an IncludeResponse object.
-    """
-    
-    def activate(self, environ):
-        response = IncludedResponse()
-        def start_response(status, headers, exc_info=None):
-            if exc_info:
-                raise exc_info[0], exc_info[1], exc_info[2]
-            response.status = status
-            response.headers = headers
-            return response.write
-        app_iter = self.application(environ, start_response)
-        try:
-            for s in app_iter:
-                response.write(s)
-        finally:
-            if hasattr(app_iter, 'close'):
-                app_iter.close()
-        response.close()
-        return response
-
-class IncludedResponse(object):
-
-    def __init__(self):
-        self.headers = None
-        self.status = None
-        self.output = StringIO()
-        self.str = None
-
-    def close(self):
-        self.str = self.output.getvalue()
-        self.output.close()
-        self.output = None
-
-    def write(self, s):
-        assert self.output is not None, (
-            "This response has already been closed and no further data "
-            "can be written.")
-        self.output.write(s)
-
-    def __str__(self):
-        return self.body
-
-    def body__get(self):
-        if self.str is None:
-            return self.output.getvalue()
-        else:
-            return self.str
-    body = property(body__get)
-
-
-class IncluderAppIter(Recursive):
-    """
-    Like Includer, but just stores the app_iter response
-    (be sure to call close on the response!)
-    """
-
-    def activate(self, environ):
-        response = IncludedAppIterResponse()
-        def start_response(status, headers, exc_info=None):
-            if exc_info:
-                raise exc_info[0], exc_info[1], exc_info[2]
-            response.status = status
-            response.headers = headers
-            return response.write
-        app_iter = self.application(environ, start_response)
-        response.app_iter = app_iter
-        return response
-
-class IncludedAppIterResponse(object):
-
-    def __init__(self):
-        self.status = None
-        self.headers = None
-        self.accumulated = []
-        self.app_iter = None
-        self._closed = False
-
-    def close(self):
-        assert not self._closed, (
-            "Tried to close twice")
-        if hasattr(self.app_iter, 'close'):
-            self.app_iter.close()
-            
-    def write(self, s):
-        self.accumulated.append
-
-def make_recursive_middleware(app, global_conf):
-    return RecursiveMiddleware(app)
-
-make_recursive_middleware.__doc__ = __doc__
diff --git a/lib/paste/registry.py b/lib/paste/registry.py
@@ -1,552 +0,0 @@
-# (c) 2005 Ben Bangert
-# This module is part of the Python Paste Project and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-"""Registry for handling request-local module globals sanely
-
-Dealing with module globals in a thread-safe way is good if your
-application is the sole responder in a thread, however that approach fails
-to properly account for various scenarios that occur with WSGI applications
-and middleware.
-
-What is actually needed in the case where a module global is desired that
-is always set properly depending on the current request, is a stacked
-thread-local object. Such an object is popped or pushed during the request
-cycle so that it properly represents the object that should be active for
-the current request.
-
-To make it easy to deal with such variables, this module provides a special
-StackedObjectProxy class which you can instantiate and attach to your
-module where you'd like others to access it. The object you'd like this to
-actually "be" during the request is then registered with the
-RegistryManager middleware, which ensures that for the scope of the current
-WSGI application everything will work properly.
-
-Example:
-
-.. code-block:: python
-    
-    #yourpackage/__init__.py
-    
-    from paste.registry import RegistryManager, StackedObjectProxy
-    myglobal = StackedObjectProxy()
-    
-    #wsgi app stack
-    app = RegistryManager(yourapp)
-    
-    #inside your wsgi app
-    class yourapp(object):
-        def __call__(self, environ, start_response):
-            obj = someobject  # The request-local object you want to access
-                              # via yourpackage.myglobal
-            if environ.has_key('paste.registry'):
-                environ['paste.registry'].register(myglobal, obj)
-
-You will then be able to import yourpackage anywhere in your WSGI app or in
-the calling stack below it and be assured that it is using the object you
-registered with Registry.
-
-RegistryManager can be in the WSGI stack multiple times, each time it
-appears it registers a new request context.
-
-
-Performance
-===========
-
-The overhead of the proxy object is very minimal, however if you are using
-proxy objects extensively (Thousands of accesses per request or more), there
-are some ways to avoid them. A proxy object runs approximately 3-20x slower
-than direct access to the object, this is rarely your performance bottleneck
-when developing web applications.
-
-Should you be developing a system which may be accessing the proxy object
-thousands of times per request, the performance of the proxy will start to
-become more noticeable. In that circumstance, the problem can be avoided by
-getting at the actual object via the proxy with the ``_current_obj`` function:
-
-.. code-block:: python
-    
-    #sessions.py
-    Session = StackedObjectProxy()
-    # ... initialization code, etc.
-    
-    # somemodule.py
-    import sessions
-    
-    def somefunc():
-        session = sessions.Session._current_obj()
-        # ... tons of session access
-
-This way the proxy is used only once to retrieve the object for the current
-context and the overhead is minimized while still making it easy to access
-the underlying object. The ``_current_obj`` function is preceded by an
-underscore to more likely avoid clashing with the contained object's
-attributes.
-
-**NOTE:** This is *highly* unlikely to be an issue in the vast majority of
-cases, and requires incredibly large amounts of proxy object access before
-one should consider the proxy object to be causing slow-downs. This section
-is provided solely in the extremely rare case that it is an issue so that a
-quick way to work around it is documented.
-
-"""
-import sys
-import paste.util.threadinglocal as threadinglocal
-
-__all__ = ['StackedObjectProxy', 'RegistryManager', 'StackedObjectRestorer',
-           'restorer']
-
-class NoDefault(object): pass
-
-class StackedObjectProxy(object):
-    """Track an object instance internally using a stack
-    
-    The StackedObjectProxy proxies access to an object internally using a
-    stacked thread-local. This makes it safe for complex WSGI environments
-    where access to the object may be desired in multiple places without
-    having to pass the actual object around.
-    
-    New objects are added to the top of the stack with _push_object while
-    objects can be removed with _pop_object. 
-    
-    """
-    def __init__(self, default=NoDefault, name="Default"):
-        """Create a new StackedObjectProxy
-        
-        If a default is given, its used in every thread if no other object
-        has been pushed on.
-        
-        """
-        self.__dict__['____name__'] = name
-        self.__dict__['____local__'] = threadinglocal.local()
-        if default is not NoDefault:
-            self.__dict__['____default_object__'] = default
-
-    def __dir__(self):
-        """Return a list of the StackedObjectProxy's and proxied
-        object's (if one exists) names.
-        """
-        dir_list = dir(self.__class__) + self.__dict__.keys()
-        try:
-            dir_list.extend(dir(self._current_obj()))
-        except TypeError:
-            pass
-        dir_list.sort()
-        return dir_list
-    
-    def __getattr__(self, attr):
-        return getattr(self._current_obj(), attr)
-    
-    def __setattr__(self, attr, value):
-        setattr(self._current_obj(), attr, value)
-    
-    def __delattr__(self, name):
-        delattr(self._current_obj(), name)
-    
-    def __getitem__(self, key):
-        return self._current_obj()[key]
-    
-    def __setitem__(self, key, value):
-        self._current_obj()[key] = value
-    
-    def __delitem__(self, key):
-        del self._current_obj()[key]
-
-    def __call__(self, *args, **kw):
-        return self._current_obj()(*args, **kw)
-    
-    def __repr__(self):
-        try:
-            return repr(self._current_obj())
-        except (TypeError, AttributeError):
-            return '<%s.%s object at 0x%x>' % (self.__class__.__module__,
-                                               self.__class__.__name__,
-                                               id(self))
-    
-    def __iter__(self):
-        return iter(self._current_obj())
-    
-    def __len__(self):
-        return len(self._current_obj())
-    
-    def __contains__(self, key):
-        return key in self._current_obj()
-
-    def __nonzero__(self):
-        return bool(self._current_obj())
-
-    def _current_obj(self):
-        """Returns the current active object being proxied to
-        
-        In the event that no object was pushed, the default object if
-        provided will be used. Otherwise, a TypeError will be raised.
-        
-        """
-        objects = getattr(self.____local__, 'objects', None)
-        if objects:
-            return objects[-1]
-        else:
-            obj = self.__dict__.get('____default_object__', NoDefault)
-            if obj is not NoDefault:
-                return obj
-            else:
-                raise TypeError(
-                    'No object (name: %s) has been registered for this '
-                    'thread' % self.____name__)
-
-    def _push_object(self, obj):
-        """Make ``obj`` the active object for this thread-local.
-        
-        This should be used like:
-        
-        .. code-block:: python
-
-            obj = yourobject()
-            module.glob = StackedObjectProxy()
-            module.glob._push_object(obj)
-            try:
-                ... do stuff ...
-            finally:
-                module.glob._pop_object(conf)
-        
-        """
-        if not hasattr(self.____local__, 'objects'):
-            self.____local__.objects = []
-        self.____local__.objects.append(obj)
-    
-    def _pop_object(self, obj=None):
-        """Remove a thread-local object.
-        
-        If ``obj`` is given, it is checked against the popped object and an
-        error is emitted if they don't match.
-        
-        """
-        if not hasattr(self.____local__, 'objects'):
-            raise AssertionError('No object has been registered for this thread')
-        popped = self.____local__.objects.pop()
-        if obj:
-            if popped is not obj:
-                raise AssertionError(
-                    'The object popped (%s) is not the same as the object '
-                    'expected (%s)' % (popped, obj))
-
-    def _object_stack(self):
-        """Returns all of the objects stacked in this container
-
-        (Might return [] if there are none)
-        """
-        try:
-            return self.____local__.objects[:]
-        except AssertionError:
-            return []
-
-    # The following methods will be swapped for their original versions by
-    # StackedObjectRestorer when restoration is enabled. The original
-    # functions (e.g. _current_obj) will be available at _current_obj_orig
-
-    def _current_obj_restoration(self):
-        request_id = restorer.in_restoration()
-        if request_id:
-            return restorer.get_saved_proxied_obj(self, request_id)
-        return self._current_obj_orig()
-    _current_obj_restoration.__doc__ = \
-        ('%s\n(StackedObjectRestorer restoration enabled)' % \
-         _current_obj.__doc__)
-
-    def _push_object_restoration(self, obj):
-        if not restorer.in_restoration():
-            self._push_object_orig(obj)
-    _push_object_restoration.__doc__ = \
-        ('%s\n(StackedObjectRestorer restoration enabled)' % \
-         _push_object.__doc__)
-
-    def _pop_object_restoration(self, obj=None):
-        if not restorer.in_restoration():
-            self._pop_object_orig(obj)
-    _pop_object_restoration.__doc__ = \
-        ('%s\n(StackedObjectRestorer restoration enabled)' % \
-         _pop_object.__doc__)
-
-class Registry(object):
-    """Track objects and stacked object proxies for removal
-    
-    The Registry object is instantiated a single time for the request no
-    matter how many times the RegistryManager is used in a WSGI stack. Each
-    RegistryManager must call ``prepare`` before continuing the call to
-    start a new context for object registering.
-    
-    Each context is tracked with a dict inside a list. The last list
-    element is the currently executing context. Each context dict is keyed
-    by the id of the StackedObjectProxy instance being proxied, the value
-    is a tuple of the StackedObjectProxy instance and the object being
-    tracked.
-    
-    """
-    def __init__(self):
-        """Create a new Registry object
-        
-        ``prepare`` must still be called before this Registry object can be
-        used to register objects.
-        
-        """
-        self.reglist = []
-    
-    def prepare(self):
-        """Used to create a new registry context
-        
-        Anytime a new RegistryManager is called, ``prepare`` needs to be
-        called on the existing Registry object. This sets up a new context
-        for registering objects.
-        
-        """
-        self.reglist.append({})
-    
-    def register(self, stacked, obj):
-        """Register an object with a StackedObjectProxy"""
-        myreglist = self.reglist[-1]
-        stacked_id = id(stacked)
-        if stacked_id in myreglist:
-            stacked._pop_object(myreglist[stacked_id][1])
-            del myreglist[stacked_id]
-        stacked._push_object(obj)
-        myreglist[stacked_id] = (stacked, obj)
-    
-    # Replace now does the same thing as register
-    replace = register
-    
-    def cleanup(self):
-        """Remove all objects from all StackedObjectProxy instances that
-        were tracked at this Registry context"""
-        for stacked, obj in self.reglist[-1].itervalues():
-            stacked._pop_object(obj)
-        self.reglist.pop()
-        
-class RegistryManager(object):
-    """Creates and maintains a Registry context
-    
-    RegistryManager creates a new registry context for the registration of
-    StackedObjectProxy instances. Multiple RegistryManager's can be in a
-    WSGI stack and will manage the context so that the StackedObjectProxies
-    always proxy to the proper object.
-    
-    The object being registered can be any object sub-class, list, or dict.
-    
-    Registering objects is done inside a WSGI application under the
-    RegistryManager instance, using the ``environ['paste.registry']``
-    object which is a Registry instance.
-        
-    """
-    def __init__(self, application, streaming=False):
-        self.application = application
-        self.streaming = streaming
-        
-    def __call__(self, environ, start_response):
-        app_iter = None
-        reg = environ.setdefault('paste.registry', Registry())
-        reg.prepare()
-        if self.streaming:
-            return self.streaming_iter(reg, environ, start_response)
-        
-        try:
-            app_iter = self.application(environ, start_response)
-        except Exception, e:
-            # Regardless of if the content is an iterable, generator, list
-            # or tuple, we clean-up right now. If its an iterable/generator
-            # care should be used to ensure the generator has its own ref
-            # to the actual object
-            if environ.get('paste.evalexception'):
-                # EvalException is present in the WSGI stack
-                expected = False
-                for expect in environ.get('paste.expected_exceptions', []):
-                    if isinstance(e, expect):
-                        expected = True
-                if not expected:
-                    # An unexpected exception: save state for EvalException
-                    restorer.save_registry_state(environ)
-            reg.cleanup()
-            raise
-        except:
-            # Save state for EvalException if it's present
-            if environ.get('paste.evalexception'):
-                restorer.save_registry_state(environ)
-            reg.cleanup()
-            raise
-        else:
-            reg.cleanup()
-        
-        return app_iter
-    
-    def streaming_iter(self, reg, environ, start_response):
-        try:
-            for item in self.application(environ, start_response):
-                yield item
-        except Exception, e:
-            # Regardless of if the content is an iterable, generator, list
-            # or tuple, we clean-up right now. If its an iterable/generator
-            # care should be used to ensure the generator has its own ref
-            # to the actual object
-            if environ.get('paste.evalexception'):
-                # EvalException is present in the WSGI stack
-                expected = False
-                for expect in environ.get('paste.expected_exceptions', []):
-                    if isinstance(e, expect):
-                        expected = True
-                if not expected:
-                    # An unexpected exception: save state for EvalException
-                    restorer.save_registry_state(environ)
-            reg.cleanup()
-            raise
-        except:
-            # Save state for EvalException if it's present
-            if environ.get('paste.evalexception'):
-                restorer.save_registry_state(environ)
-            reg.cleanup()
-            raise
-        else:
-            reg.cleanup()
-
-
-class StackedObjectRestorer(object):
-    """Track StackedObjectProxies and their proxied objects for automatic
-    restoration within EvalException's interactive debugger.
-
-    An instance of this class tracks all StackedObjectProxy state in existence
-    when unexpected exceptions are raised by WSGI applications housed by
-    EvalException and RegistryManager. Like EvalException, this information is
-    stored for the life of the process.
-
-    When an unexpected exception occurs and EvalException is present in the
-    WSGI stack, save_registry_state is intended to be called to store the
-    Registry state and enable automatic restoration on all currently registered
-    StackedObjectProxies.
-
-    With restoration enabled, those StackedObjectProxies' _current_obj
-    (overwritten by _current_obj_restoration) method's strategy is modified:
-    it will return its appropriate proxied object from the restorer when
-    a restoration context is active in the current thread.
-
-    The StackedObjectProxies' _push/pop_object methods strategies are also
-    changed: they no-op when a restoration context is active in the current
-    thread (because the pushing/popping work is all handled by the
-    Registry/restorer).
-
-    The request's Registry objects' reglists are restored from the restorer
-    when a restoration context begins, enabling the Registry methods to work
-    while their changes are tracked by the restorer.
-
-    The overhead of enabling restoration is negligible (another threadlocal
-    access for the changed StackedObjectProxy methods) for normal use outside
-    of a restoration context, but worth mentioning when combined with
-    StackedObjectProxies normal overhead. Once enabled it does not turn off,
-    however:
-
-    o Enabling restoration only occurs after an unexpected exception is
-    detected. The server is likely to be restarted shortly after the exception
-    is raised to fix the cause
-
-    o StackedObjectRestorer is only enabled when EvalException is enabled (not
-    on a production server) and RegistryManager exists in the middleware
-    stack"""
-    def __init__(self):
-        # Registries and their saved reglists by request_id
-        self.saved_registry_states = {}
-        self.restoration_context_id = threadinglocal.local()
-
-    def save_registry_state(self, environ):
-        """Save the state of this request's Registry (if it hasn't already been
-        saved) to the saved_registry_states dict, keyed by the request's unique
-        identifier"""
-        registry = environ.get('paste.registry')
-        if not registry or not len(registry.reglist) or \
-                self.get_request_id(environ) in self.saved_registry_states:
-            # No Registry, no state to save, or this request's state has
-            # already been saved
-            return
-
-        self.saved_registry_states[self.get_request_id(environ)] = \
-            (registry, registry.reglist[:])
-
-        # Tweak the StackedObjectProxies we want to save state for -- change
-        # their methods to act differently when a restoration context is active
-        # in the current thread
-        for reglist in registry.reglist:
-            for stacked, obj in reglist.itervalues():
-                self.enable_restoration(stacked)
-
-    def get_saved_proxied_obj(self, stacked, request_id):
-        """Retrieve the saved object proxied by the specified
-        StackedObjectProxy for the request identified by request_id"""
-        # All state for the request identified by request_id
-        reglist = self.saved_registry_states[request_id][1]
-
-        # The top of the stack was current when the exception occurred
-        stack_level = len(reglist) - 1
-        stacked_id = id(stacked)
-        while True:
-            if stack_level < 0:
-                # Nothing registered: Call _current_obj_orig to raise a
-                # TypeError
-                return stacked._current_obj_orig()
-            context = reglist[stack_level]
-            if stacked_id in context:
-                break
-            # This StackedObjectProxy may not have been registered by the
-            # RegistryManager that was active when the exception was raised --
-            # continue searching down the stack until it's found
-            stack_level -= 1
-        return context[stacked_id][1]
-
-    def enable_restoration(self, stacked):
-        """Replace the specified StackedObjectProxy's methods with their
-        respective restoration versions.
-
-        _current_obj_restoration forces recovery of the saved proxied object
-        when a restoration context is active in the current thread.
-
-        _push/pop_object_restoration avoid pushing/popping data
-        (pushing/popping is only done at the Registry level) when a restoration
-        context is active in the current thread"""
-        if '_current_obj_orig' in stacked.__dict__:
-            # Restoration already enabled
-            return
-
-        for func_name in ('_current_obj', '_push_object', '_pop_object'):
-            orig_func = getattr(stacked, func_name)
-            restoration_func = getattr(stacked, func_name + '_restoration')
-            stacked.__dict__[func_name + '_orig'] = orig_func
-            stacked.__dict__[func_name] = restoration_func
-
-    def get_request_id(self, environ):
-        """Return a unique identifier for the current request"""
-        from paste.evalexception.middleware import get_debug_count
-        return get_debug_count(environ)
-
-    def restoration_begin(self, request_id):
-        """Enable a restoration context in the current thread for the specified
-        request_id"""
-        if request_id in self.saved_registry_states:
-            # Restore the old Registry object's state
-            registry, reglist = self.saved_registry_states[request_id]
-            registry.reglist = reglist
-
-        self.restoration_context_id.request_id = request_id
-
-    def restoration_end(self):
-        """Register a restoration context as finished, if one exists"""
-        try:
-            del self.restoration_context_id.request_id
-        except AttributeError:
-            pass
-
-    def in_restoration(self):
-        """Determine if a restoration context is active for the current thread.
-        Returns the request_id it's active for if so, otherwise False"""
-        return getattr(self.restoration_context_id, 'request_id', False)
-
-restorer = StackedObjectRestorer()
-
-
-# Paste Deploy entry point
-def make_registry_manager(app, global_conf):
-    return RegistryManager(app)
-
-make_registry_manager.__doc__ = RegistryManager.__doc__
diff --git a/lib/paste/reloader.py b/lib/paste/reloader.py
@@ -1,178 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-A file monitor and server restarter.
-
-Use this like:
-
-..code-block:: Python
-
-    import reloader
-    reloader.install()
-
-Then make sure your server is installed with a shell script like::
-
-    err=3
-    while test "$err" -eq 3 ; do
-        python server.py
-        err="$?"
-    done
-
-or is run from this .bat file (if you use Windows)::
-
-    @echo off
-    :repeat
-        python server.py
-    if %errorlevel% == 3 goto repeat
-
-or run a monitoring process in Python (``paster serve --reload`` does
-this).  
-
-Use the ``watch_file(filename)`` function to cause a reload/restart for
-other other non-Python files (e.g., configuration files).  If you have
-a dynamic set of files that grows over time you can use something like::
-
-    def watch_config_files():
-        return CONFIG_FILE_CACHE.keys()
-    paste.reloader.add_file_callback(watch_config_files)
-
-Then every time the reloader polls files it will call
-``watch_config_files`` and check all the filenames it returns.
-"""
-
-import os
-import sys
-import time
-import threading
-import traceback
-from paste.util.classinstance import classinstancemethod
-
-def install(poll_interval=1):
-    """
-    Install the reloading monitor.
-
-    On some platforms server threads may not terminate when the main
-    thread does, causing ports to remain open/locked.  The
-    ``raise_keyboard_interrupt`` option creates a unignorable signal
-    which causes the whole application to shut-down (rudely).
-    """
-    mon = Monitor(poll_interval=poll_interval)
-    t = threading.Thread(target=mon.periodic_reload)
-    t.setDaemon(True)
-    t.start()
-
-class Monitor(object):
-
-    instances = []
-    global_extra_files = []
-    global_file_callbacks = []
-
-    def __init__(self, poll_interval):
-        self.module_mtimes = {}
-        self.keep_running = True
-        self.poll_interval = poll_interval
-        self.extra_files = list(self.global_extra_files)
-        self.instances.append(self)
-        self.file_callbacks = list(self.global_file_callbacks)
-
-    def periodic_reload(self):
-        while True:
-            if not self.check_reload():
-                # use os._exit() here and not sys.exit() since within a
-                # thread sys.exit() just closes the given thread and
-                # won't kill the process; note os._exit does not call
-                # any atexit callbacks, nor does it do finally blocks,
-                # flush open files, etc.  In otherwords, it is rude.
-                os._exit(3)
-                break
-            time.sleep(self.poll_interval)
-
-    def check_reload(self):
-        filenames = list(self.extra_files)
-        for file_callback in self.file_callbacks:
-            try:
-                filenames.extend(file_callback())
-            except:
-                print >> sys.stderr, "Error calling paste.reloader callback %r:" % file_callback
-                traceback.print_exc()
-        for module in sys.modules.values():
-            try:
-                filename = module.__file__
-            except (AttributeError, ImportError), exc:
-                continue
-            if filename is not None:
-                filenames.append(filename)
-        for filename in filenames:
-            try:
-                stat = os.stat(filename)
-                if stat:
-                    mtime = stat.st_mtime
-                else:
-                    mtime = 0
-            except (OSError, IOError):
-                continue
-            if filename.endswith('.pyc') and os.path.exists(filename[:-1]):
-                mtime = max(os.stat(filename[:-1]).st_mtime, mtime)
-            elif filename.endswith('$py.class') and \
-                    os.path.exists(filename[:-9] + '.py'):
-                mtime = max(os.stat(filename[:-9] + '.py').st_mtime, mtime)
-            if not self.module_mtimes.has_key(filename):
-                self.module_mtimes[filename] = mtime
-            elif self.module_mtimes[filename] < mtime:
-                print >> sys.stderr, (
-                    "%s changed; reloading..." % filename)
-                return False
-        return True
-
-    def watch_file(self, cls, filename):
-        """Watch the named file for changes"""
-        filename = os.path.abspath(filename)
-        if self is None:
-            for instance in cls.instances:
-                instance.watch_file(filename)
-            cls.global_extra_files.append(filename)
-        else:
-            self.extra_files.append(filename)
-
-    watch_file = classinstancemethod(watch_file)
-
-    def add_file_callback(self, cls, callback):
-        """Add a callback -- a function that takes no parameters -- that will
-        return a list of filenames to watch for changes."""
-        if self is None:
-            for instance in cls.instances:
-                instance.add_file_callback(callback)
-            cls.global_file_callbacks.append(callback)
-        else:
-            self.file_callbacks.append(callback)
-
-    add_file_callback = classinstancemethod(add_file_callback)
-
-if sys.platform.startswith('java'):
-    try:
-        from _systemrestart import SystemRestart
-    except ImportError:
-        pass
-    else:
-        class JythonMonitor(Monitor):
-
-            """
-            Monitor that utilizes Jython's special
-            ``_systemrestart.SystemRestart`` exception.
-
-            When raised from the main thread it causes Jython to reload
-            the interpreter in the existing Java process (avoiding
-            startup time).
-
-            Note that this functionality of Jython is experimental and
-            may change in the future.
-            """
-
-            def periodic_reload(self):
-                while True:
-                    if not self.check_reload():
-                        raise SystemRestart()
-                    time.sleep(self.poll_interval)
-
-watch_file = Monitor.watch_file
-add_file_callback = Monitor.add_file_callback
diff --git a/lib/paste/request.py b/lib/paste/request.py
@@ -1,405 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-# (c) 2005 Ian Bicking and contributors
-# This module is part of the Python Paste Project and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-"""
-This module provides helper routines with work directly on a WSGI
-environment to solve common requirements.
-
-   * get_cookies(environ)
-   * parse_querystring(environ)
-   * parse_formvars(environ, include_get_vars=True)
-   * construct_url(environ, with_query_string=True, with_path_info=True,
-                   script_name=None, path_info=None, querystring=None)
-   * path_info_split(path_info)
-   * path_info_pop(environ)
-   * resolve_relative_url(url, environ)
-
-"""
-import cgi
-from Cookie import SimpleCookie
-from StringIO import StringIO
-import urlparse
-import urllib
-try:
-    from UserDict import DictMixin
-except ImportError:
-    from paste.util.UserDict24 import DictMixin
-from paste.util.multidict import MultiDict
-
-__all__ = ['get_cookies', 'get_cookie_dict', 'parse_querystring',
-           'parse_formvars', 'construct_url', 'path_info_split',
-           'path_info_pop', 'resolve_relative_url', 'EnvironHeaders']
-
-def get_cookies(environ):
-    """
-    Gets a cookie object (which is a dictionary-like object) from the
-    request environment; caches this value in case get_cookies is
-    called again for the same request.
-
-    """
-    header = environ.get('HTTP_COOKIE', '')
-    if environ.has_key('paste.cookies'):
-        cookies, check_header = environ['paste.cookies']
-        if check_header == header:
-            return cookies
-    cookies = SimpleCookie()
-    cookies.load(header)
-    environ['paste.cookies'] = (cookies, header)
-    return cookies
-
-def get_cookie_dict(environ):
-    """Return a *plain* dictionary of cookies as found in the request.
-
-    Unlike ``get_cookies`` this returns a dictionary, not a
-    ``SimpleCookie`` object.  For incoming cookies a dictionary fully
-    represents the information.  Like ``get_cookies`` this caches and
-    checks the cache.
-    """
-    header = environ.get('HTTP_COOKIE')
-    if not header:
-        return {}
-    if environ.has_key('paste.cookies.dict'):
-        cookies, check_header = environ['paste.cookies.dict']
-        if check_header == header:
-            return cookies
-    cookies = SimpleCookie()
-    cookies.load(header)
-    result = {}
-    for name in cookies:
-        result[name] = cookies[name].value
-    environ['paste.cookies.dict'] = (result, header)
-    return result
-
-def parse_querystring(environ):
-    """
-    Parses a query string into a list like ``[(name, value)]``.
-    Caches this value in case parse_querystring is called again
-    for the same request.
-
-    You can pass the result to ``dict()``, but be aware that keys that
-    appear multiple times will be lost (only the last value will be
-    preserved).
-
-    """
-    source = environ.get('QUERY_STRING', '')
-    if not source:
-        return []
-    if 'paste.parsed_querystring' in environ:
-        parsed, check_source = environ['paste.parsed_querystring']
-        if check_source == source:
-            return parsed
-    parsed = cgi.parse_qsl(source, keep_blank_values=True,
-                           strict_parsing=False)
-    environ['paste.parsed_querystring'] = (parsed, source)
-    return parsed
-
-def parse_dict_querystring(environ):
-    """Parses a query string like parse_querystring, but returns a MultiDict
-
-    Caches this value in case parse_dict_querystring is called again
-    for the same request.
-
-    Example::
-
-        >>> environ = {'QUERY_STRING': 'day=Monday&user=fred&user=jane'}
-        >>> parsed = parse_dict_querystring(environ)
-
-        >>> parsed['day']
-        'Monday'
-        >>> parsed['user']
-        'fred'
-        >>> parsed.getall('user')
-        ['fred', 'jane']
-
-    """
-    source = environ.get('QUERY_STRING', '')
-    if not source:
-        return MultiDict()
-    if 'paste.parsed_dict_querystring' in environ:
-        parsed, check_source = environ['paste.parsed_dict_querystring']
-        if check_source == source:
-            return parsed
-    parsed = cgi.parse_qsl(source, keep_blank_values=True,
-                           strict_parsing=False)
-    multi = MultiDict(parsed)
-    environ['paste.parsed_dict_querystring'] = (multi, source)
-    return multi
-
-def parse_formvars(environ, include_get_vars=True):
-    """Parses the request, returning a MultiDict of form variables.
-
-    If ``include_get_vars`` is true then GET (query string) variables
-    will also be folded into the MultiDict.
-
-    All values should be strings, except for file uploads which are
-    left as ``FieldStorage`` instances.
-
-    If the request was not a normal form request (e.g., a POST with an
-    XML body) then ``environ['wsgi.input']`` won't be read.
-    """
-    source = environ['wsgi.input']
-    if 'paste.parsed_formvars' in environ:
-        parsed, check_source = environ['paste.parsed_formvars']
-        if check_source == source:
-            if include_get_vars:
-                parsed.update(parse_querystring(environ))
-            return parsed
-    # @@: Shouldn't bother FieldStorage parsing during GET/HEAD and
-    # fake_out_cgi requests
-    type = environ.get('CONTENT_TYPE', '').lower()
-    if ';' in type:
-        type = type.split(';', 1)[0]
-    fake_out_cgi = type not in ('', 'application/x-www-form-urlencoded',
-                                'multipart/form-data')
-    # FieldStorage assumes a default CONTENT_LENGTH of -1, but a
-    # default of 0 is better:
-    if not environ.get('CONTENT_LENGTH'):
-        environ['CONTENT_LENGTH'] = '0'
-    # Prevent FieldStorage from parsing QUERY_STRING during GET/HEAD
-    # requests
-    old_query_string = environ.get('QUERY_STRING','')
-    environ['QUERY_STRING'] = ''
-    if fake_out_cgi:
-        input = StringIO('')
-        old_content_type = environ.get('CONTENT_TYPE')
-        old_content_length = environ.get('CONTENT_LENGTH')
-        environ['CONTENT_LENGTH'] = '0'
-        environ['CONTENT_TYPE'] = ''    
-    else:
-        input = environ['wsgi.input']
-    fs = cgi.FieldStorage(fp=input,
-                          environ=environ,
-                          keep_blank_values=1)
-    environ['QUERY_STRING'] = old_query_string
-    if fake_out_cgi:
-        environ['CONTENT_TYPE'] = old_content_type
-        environ['CONTENT_LENGTH'] = old_content_length
-    formvars = MultiDict()
-    if isinstance(fs.value, list):
-        for name in fs.keys():
-            values = fs[name]
-            if not isinstance(values, list):
-                values = [values]
-            for value in values:
-                if not value.filename:
-                    value = value.value
-                formvars.add(name, value)
-    environ['paste.parsed_formvars'] = (formvars, source)
-    if include_get_vars:
-        formvars.update(parse_querystring(environ))
-    return formvars
-
-def construct_url(environ, with_query_string=True, with_path_info=True,
-                  script_name=None, path_info=None, querystring=None):
-    """Reconstructs the URL from the WSGI environment.
-
-    You may override SCRIPT_NAME, PATH_INFO, and QUERYSTRING with
-    the keyword arguments.
-
-    """
-    url = environ['wsgi.url_scheme']+'://'
-
-    if environ.get('HTTP_HOST'):
-        host = environ['HTTP_HOST']
-        port = None
-        if ':' in host:
-            host, port = host.split(':', 1)
-            if environ['wsgi.url_scheme'] == 'https':
-                if port == '443':
-                    port = None
-            elif environ['wsgi.url_scheme'] == 'http':
-                if port == '80':
-                    port = None
-        url += host
-        if port:
-            url += ':%s' % port
-    else:
-        url += environ['SERVER_NAME']
-        if environ['wsgi.url_scheme'] == 'https':
-            if environ['SERVER_PORT'] != '443':
-                url += ':' + environ['SERVER_PORT']
-        else:
-            if environ['SERVER_PORT'] != '80':
-                url += ':' + environ['SERVER_PORT']
-
-    if script_name is None:
-        url += urllib.quote(environ.get('SCRIPT_NAME',''))
-    else:
-        url += urllib.quote(script_name)
-    if with_path_info:
-        if path_info is None:
-            url += urllib.quote(environ.get('PATH_INFO',''))
-        else:
-            url += urllib.quote(path_info)
-    if with_query_string:
-        if querystring is None:
-            if environ.get('QUERY_STRING'):
-                url += '?' + environ['QUERY_STRING']
-        elif querystring:
-            url += '?' + querystring
-    return url
-
-def resolve_relative_url(url, environ):
-    """
-    Resolve the given relative URL as being relative to the
-    location represented by the environment.  This can be used
-    for redirecting to a relative path.  Note: if url is already
-    absolute, this function will (intentionally) have no effect
-    on it.
-
-    """
-    cur_url = construct_url(environ, with_query_string=False)
-    return urlparse.urljoin(cur_url, url)
-
-def path_info_split(path_info):
-    """
-    Splits off the first segment of the path.  Returns (first_part,
-    rest_of_path).  first_part can be None (if PATH_INFO is empty), ''
-    (if PATH_INFO is '/'), or a name without any /'s.  rest_of_path
-    can be '' or a string starting with /.
-
-    """
-    if not path_info:
-        return None, ''
-    assert path_info.startswith('/'), (
-        "PATH_INFO should start with /: %r" % path_info)
-    path_info = path_info.lstrip('/')
-    if '/' in path_info:
-        first, rest = path_info.split('/', 1)
-        return first, '/' + rest
-    else:
-        return path_info, ''
-
-def path_info_pop(environ):
-    """
-    'Pops' off the next segment of PATH_INFO, pushing it onto
-    SCRIPT_NAME, and returning that segment.
-
-    For instance::
-
-        >>> def call_it(script_name, path_info):
-        ...     env = {'SCRIPT_NAME': script_name, 'PATH_INFO': path_info}
-        ...     result = path_info_pop(env)
-        ...     print 'SCRIPT_NAME=%r; PATH_INFO=%r; returns=%r' % (
-        ...         env['SCRIPT_NAME'], env['PATH_INFO'], result)
-        >>> call_it('/foo', '/bar')
-        SCRIPT_NAME='/foo/bar'; PATH_INFO=''; returns='bar'
-        >>> call_it('/foo/bar', '')
-        SCRIPT_NAME='/foo/bar'; PATH_INFO=''; returns=None
-        >>> call_it('/foo/bar', '/')
-        SCRIPT_NAME='/foo/bar/'; PATH_INFO=''; returns=''
-        >>> call_it('', '/1/2/3')
-        SCRIPT_NAME='/1'; PATH_INFO='/2/3'; returns='1'
-        >>> call_it('', '//1/2')
-        SCRIPT_NAME='//1'; PATH_INFO='/2'; returns='1'
-
-    """
-    path = environ.get('PATH_INFO', '')
-    if not path:
-        return None
-    while path.startswith('/'):
-        environ['SCRIPT_NAME'] += '/'
-        path = path[1:]
-    if '/' not in path:
-        environ['SCRIPT_NAME'] += path
-        environ['PATH_INFO'] = ''
-        return path
-    else:
-        segment, path = path.split('/', 1)
-        environ['PATH_INFO'] = '/' + path
-        environ['SCRIPT_NAME'] += segment
-        return segment
-
-_parse_headers_special = {
-    # This is a Zope convention, but we'll allow it here:
-    'HTTP_CGI_AUTHORIZATION': 'Authorization',
-    'CONTENT_LENGTH': 'Content-Length',
-    'CONTENT_TYPE': 'Content-Type',
-    }
-
-def parse_headers(environ):
-    """
-    Parse the headers in the environment (like ``HTTP_HOST``) and
-    yield a sequence of those (header_name, value) tuples.
-    """
-    # @@: Maybe should parse out comma-separated headers?
-    for cgi_var, value in environ.iteritems():
-        if cgi_var in _parse_headers_special:
-            yield _parse_headers_special[cgi_var], value
-        elif cgi_var.startswith('HTTP_'):
-            yield cgi_var[5:].title().replace('_', '-'), value
-
-class EnvironHeaders(DictMixin):
-    """An object that represents the headers as present in a
-    WSGI environment.
-
-    This object is a wrapper (with no internal state) for a WSGI
-    request object, representing the CGI-style HTTP_* keys as a
-    dictionary.  Because a CGI environment can only hold one value for
-    each key, this dictionary is single-valued (unlike outgoing
-    headers).
-    """
-
-    def __init__(self, environ):
-        self.environ = environ
-
-    def _trans_name(self, name):
-        key = 'HTTP_'+name.replace('-', '_').upper()
-        if key == 'HTTP_CONTENT_LENGTH':
-            key = 'CONTENT_LENGTH'
-        elif key == 'HTTP_CONTENT_TYPE':
-            key = 'CONTENT_TYPE'
-        return key
-
-    def _trans_key(self, key):
-        if key == 'CONTENT_TYPE':
-            return 'Content-Type'
-        elif key == 'CONTENT_LENGTH':
-            return 'Content-Length'
-        elif key.startswith('HTTP_'):
-            return key[5:].replace('_', '-').title()
-        else:
-            return None
-        
-    def __getitem__(self, item):
-        return self.environ[self._trans_name(item)]
-
-    def __setitem__(self, item, value):
-        # @@: Should this dictionary be writable at all?
-        self.environ[self._trans_name(item)] = value
-
-    def __delitem__(self, item):
-        del self.environ[self._trans_name(item)]
-
-    def __iter__(self):
-        for key in self.environ:
-            name = self._trans_key(key)
-            if name is not None:
-                yield name
-
-    def keys(self):
-        return list(iter(self))
-
-    def __contains__(self, item):
-        return self._trans_name(item) in self.environ
-
-def _cgi_FieldStorage__repr__patch(self):
-    """ monkey patch for FieldStorage.__repr__
-
-    Unbelievely, the default __repr__ on FieldStorage reads
-    the entire file content instead of being sane about it.
-    This is a simple replacement that doesn't do that
-    """
-    if self.file:
-        return "FieldStorage(%r, %r)" % (
-                self.name, self.filename)
-    return "FieldStorage(%r, %r, %r)" % (
-             self.name, self.filename, self.value)
-
-cgi.FieldStorage.__repr__ = _cgi_FieldStorage__repr__patch
-
-if __name__ == '__main__':
-    import doctest
-    doctest.testmod()
diff --git a/lib/paste/response.py b/lib/paste/response.py
@@ -1,240 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""Routines to generate WSGI responses"""
-
-############################################################
-## Headers
-############################################################
-import warnings
-
-class HeaderDict(dict):
-
-    """
-    This represents response headers.  It handles the headers as a
-    dictionary, with case-insensitive keys.
-
-    Also there is an ``.add(key, value)`` method, which sets the key,
-    or adds the value to the current value (turning it into a list if
-    necessary).
-
-    For passing to WSGI there is a ``.headeritems()`` method which is
-    like ``.items()`` but unpacks value that are lists.  It also
-    handles encoding -- all headers are encoded in ASCII (if they are
-    unicode).
-
-    @@: Should that encoding be ISO-8859-1 or UTF-8?  I'm not sure
-    what the spec says.
-    """
-
-    def __getitem__(self, key):
-        return dict.__getitem__(self, self.normalize(key))
-
-    def __setitem__(self, key, value):
-        dict.__setitem__(self, self.normalize(key), value)
-
-    def __delitem__(self, key):
-        dict.__delitem__(self, self.normalize(key))
-
-    def __contains__(self, key):
-        return dict.__contains__(self, self.normalize(key))
-
-    has_key = __contains__
-
-    def get(self, key, failobj=None):
-        return dict.get(self, self.normalize(key), failobj)
-
-    def setdefault(self, key, failobj=None):
-        return dict.setdefault(self, self.normalize(key), failobj)
-        
-    def pop(self, key):
-        return dict.pop(self, self.normalize(key))
-
-    def update(self, other):
-        for key in other:
-            self[self.normalize(key)] = other[key]
-
-    def normalize(self, key):
-        return str(key).lower().strip()
-
-    def add(self, key, value):
-        key = self.normalize(key)
-        if key in self:
-            if isinstance(self[key], list):
-                self[key].append(value)
-            else:
-                self[key] = [self[key], value]
-        else:
-            self[key] = value
-
-    def headeritems(self):
-        result = []
-        for key, value in self.items():
-            if isinstance(value, list):
-                for v in value:
-                    result.append((key, str(v)))
-            else:
-                result.append((key, str(value)))
-        return result
-
-    #@classmethod
-    def fromlist(cls, seq):
-        self = cls()
-        for name, value in seq:
-            self.add(name, value)
-        return self
-    
-    fromlist = classmethod(fromlist)
-
-def has_header(headers, name):
-    """
-    Is header named ``name`` present in headers?
-    """
-    name = name.lower()
-    for header, value in headers:
-        if header.lower() == name:
-            return True
-    return False
-
-def header_value(headers, name):
-    """
-    Returns the header's value, or None if no such header.  If a
-    header appears more than once, all the values of the headers
-    are joined with ','.   Note that this is consistent /w RFC 2616
-    section 4.2 which states:
-
-        It MUST be possible to combine the multiple header fields
-        into one "field-name: field-value" pair, without changing
-        the semantics of the message, by appending each subsequent
-        field-value to the first, each separated by a comma.
-
-    However, note that the original netscape usage of 'Set-Cookie',
-    especially in MSIE which contains an 'expires' date will is not
-    compatible with this particular concatination method.
-    """
-    name = name.lower()
-    result = [value for header, value in headers
-              if header.lower() == name]
-    if result:
-        return ','.join(result)
-    else:
-        return None
-
-def remove_header(headers, name):
-    """
-    Removes the named header from the list of headers.  Returns the
-    value of that header, or None if no header found.  If multiple
-    headers are found, only the last one is returned.
-    """
-    name = name.lower()
-    i = 0
-    result = None
-    while i < len(headers):
-        if headers[i][0].lower() == name:
-            result = headers[i][1]
-            del headers[i]
-            continue
-        i += 1
-    return result
-
-def replace_header(headers, name, value):
-    """
-    Updates the headers replacing the first occurance of the given name
-    with the value provided; asserting that no further occurances
-    happen. Note that this is _not_ the same as remove_header and then
-    append, as two distinct operations (del followed by an append) are
-    not atomic in a threaded environment. Returns the previous header
-    value for the provided name, if any.   Clearly one should not use
-    this function with ``set-cookie`` or other names that may have more
-    than one occurance in the headers.
-    """
-    name = name.lower()
-    i = 0
-    result = None
-    while i < len(headers):
-        if headers[i][0].lower() == name:
-            assert not result, "two values for the header '%s' found" % name
-            result = headers[i][1]
-            headers[i] = (name, value)
-        i += 1
-    if not result:
-        headers.append((name, value))
-    return result
-
-
-############################################################
-## Deprecated methods
-############################################################
-
-def error_body_response(error_code, message, __warn=True):
-    """
-    Returns a standard HTML response page for an HTTP error.
-    **Note:** Deprecated
-    """
-    if __warn:
-        warnings.warn(
-            'wsgilib.error_body_response is deprecated; use the '
-            'wsgi_application method on an HTTPException object '
-            'instead', DeprecationWarning, 2)
-    return '''\
-<html>
-  <head>
-    <title>%(error_code)s</title>
-  </head>
-  <body>
-  <h1>%(error_code)s</h1>
-  %(message)s
-  </body>
-</html>''' % {
-        'error_code': error_code,
-        'message': message,
-        }
-
-
-def error_response(environ, error_code, message,
-                   debug_message=None, __warn=True):
-    """
-    Returns the status, headers, and body of an error response.
-
-    Use like:
-    
-    .. code-block:: python
-
-        status, headers, body = wsgilib.error_response(
-            '301 Moved Permanently', 'Moved to <a href="%s">%s</a>'
-            % (url, url))
-        start_response(status, headers)
-        return [body]
-    
-    **Note:** Deprecated
-    """
-    if __warn:
-        warnings.warn(
-            'wsgilib.error_response is deprecated; use the '
-            'wsgi_application method on an HTTPException object '
-            'instead', DeprecationWarning, 2)
-    if debug_message and environ.get('paste.config', {}).get('debug'):
-        message += '\n\n<!-- %s -->' % debug_message
-    body = error_body_response(error_code, message, __warn=False)
-    headers = [('content-type', 'text/html'),
-               ('content-length', str(len(body)))]
-    return error_code, headers, body
-
-def error_response_app(error_code, message, debug_message=None,
-                       __warn=True):
-    """
-    An application that emits the given error response.
-
-    **Note:** Deprecated
-    """
-    if __warn:
-        warnings.warn(
-            'wsgilib.error_response_app is deprecated; use the '
-            'wsgi_application method on an HTTPException object '
-            'instead', DeprecationWarning, 2)
-    def application(environ, start_response):
-        status, headers, body = error_response(
-            environ, error_code, message,
-            debug_message=debug_message, __warn=False)
-        start_response(status, headers)
-        return [body]
-    return application
diff --git a/lib/paste/session.py b/lib/paste/session.py
@@ -1,337 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-"""
-Creates a session object in your WSGI environment.
-
-Use like:
-
-..code-block:: Python
-
-    environ['paste.session.factory']()
-
-This will return a dictionary.  The contents of this dictionary will
-be saved to disk when the request is completed.  The session will be
-created when you first fetch the session dictionary, and a cookie will
-be sent in that case.  There's current no way to use sessions without
-cookies, and there's no way to delete a session except to clear its
-data.
-
-@@: This doesn't do any locking, and may cause problems when a single
-session is accessed concurrently.  Also, it loads and saves the
-session for each request, with no caching.  Also, sessions aren't
-expired.
-"""
-
-from Cookie import SimpleCookie
-import time
-import random
-import os
-import datetime
-import threading
-import tempfile
-
-try:
-    import cPickle
-except ImportError:
-    import pickle as cPickle
-try:
-    from hashlib import md5
-except ImportError:
-    from md5 import md5
-from paste import wsgilib
-from paste import request
-
-class SessionMiddleware(object):
-
-    def __init__(self, application, global_conf=None, **factory_kw):
-        self.application = application
-        self.factory_kw = factory_kw
-
-    def __call__(self, environ, start_response):
-        session_factory = SessionFactory(environ, **self.factory_kw)
-        environ['paste.session.factory'] = session_factory
-        remember_headers = []
-
-        def session_start_response(status, headers, exc_info=None):
-            if not session_factory.created:
-                remember_headers[:] = [status, headers]
-                return start_response(status, headers)
-            headers.append(session_factory.set_cookie_header())
-            return start_response(status, headers, exc_info)
-
-        app_iter = self.application(environ, session_start_response)
-        def start():
-            if session_factory.created and remember_headers:
-                # Tricky bastard used the session after start_response
-                status, headers = remember_headers
-                headers.append(session_factory.set_cookie_header())
-                exc = ValueError(
-                    "You cannot get the session after content from the "
-                    "app_iter has been returned")
-                start_response(status, headers, (exc.__class__, exc, None))
-        def close():
-            if session_factory.used:
-                session_factory.close()
-        return wsgilib.add_start_close(app_iter, start, close)
-
-
-class SessionFactory(object):
-
-
-    def __init__(self, environ, cookie_name='_SID_',
-                 session_class=None,
-                 session_expiration=60*12, # in minutes
-                 **session_class_kw):
-
-        self.created = False
-        self.used = False
-        self.environ = environ
-        self.cookie_name = cookie_name
-        self.session = None
-        self.session_class = session_class or FileSession
-        self.session_class_kw = session_class_kw
-
-        self.expiration = session_expiration
-
-    def __call__(self):
-        self.used = True
-        if self.session is not None:
-            return self.session.data()
-        cookies = request.get_cookies(self.environ)
-        session = None
-        if cookies.has_key(self.cookie_name):
-            self.sid = cookies[self.cookie_name].value
-            try:
-                session = self.session_class(self.sid, create=False,
-                                             **self.session_class_kw)
-            except KeyError:
-                # Invalid SID
-                pass
-        if session is None:
-            self.created = True
-            self.sid = self.make_sid()
-            session = self.session_class(self.sid, create=True,
-                                         **self.session_class_kw)
-        session.clean_up()
-        self.session = session
-        return session.data()
-
-    def has_session(self):
-        if self.session is not None:
-            return True
-        cookies = request.get_cookies(self.environ)
-        if cookies.has_key(self.cookie_name):
-            return True
-        return False
-
-    def make_sid(self):
-        # @@: need better algorithm
-        return (''.join(['%02d' % x for x in time.localtime(time.time())[:6]])
-                + '-' + self.unique_id())
-
-    def unique_id(self, for_object=None):
-        """
-        Generates an opaque, identifier string that is practically
-        guaranteed to be unique.  If an object is passed, then its
-        id() is incorporated into the generation.  Relies on md5 and
-        returns a 32 character long string.
-        """
-        r = [time.time(), random.random()]
-        if hasattr(os, 'times'):
-            r.append(os.times())
-        if for_object is not None:
-            r.append(id(for_object))
-        md5_hash = md5(str(r))
-        try:
-            return md5_hash.hexdigest()
-        except AttributeError:
-            # Older versions of Python didn't have hexdigest, so we'll
-            # do it manually
-            hexdigest = []
-            for char in md5_hash.digest():
-                hexdigest.append('%02x' % ord(char))
-            return ''.join(hexdigest)
-
-    def set_cookie_header(self):
-        c = SimpleCookie()
-        c[self.cookie_name] = self.sid
-        c[self.cookie_name]['path'] = '/'
-
-        gmt_expiration_time = time.gmtime(time.time() + (self.expiration * 60))
-        c[self.cookie_name]['expires'] = time.strftime("%a, %d-%b-%Y %H:%M:%S GMT", gmt_expiration_time)
-
-        name, value = str(c).split(': ', 1)
-        return (name, value)
-
-    def close(self):
-        if self.session is not None:
-            self.session.close()
-
-
-last_cleanup = None
-cleaning_up = False
-cleanup_cycle = datetime.timedelta(seconds=15*60) #15 min
-
-class FileSession(object):
-
-    def __init__(self, sid, create=False, session_file_path=tempfile.gettempdir(),
-                 chmod=None,
-                 expiration=2880, # in minutes: 48 hours
-                 ):
-        if chmod and isinstance(chmod, basestring):
-            chmod = int(chmod, 8)
-        self.chmod = chmod
-        if not sid:
-            # Invalid...
-            raise KeyError
-        self.session_file_path = session_file_path
-        self.sid = sid
-        if not create:
-            if not os.path.exists(self.filename()):
-                raise KeyError
-        self._data = None
-
-        self.expiration = expiration
-
-
-    def filename(self):
-        return os.path.join(self.session_file_path, self.sid)
-
-    def data(self):
-        if self._data is not None:
-            return self._data
-        if os.path.exists(self.filename()):
-            f = open(self.filename(), 'rb')
-            self._data = cPickle.load(f)
-            f.close()
-        else:
-            self._data = {}
-        return self._data
-
-    def close(self):
-        if self._data is not None:
-            filename = self.filename()
-            exists = os.path.exists(filename)
-            if not self._data:
-                if exists:
-                    os.unlink(filename)
-            else:
-                f = open(filename, 'wb')
-                cPickle.dump(self._data, f)
-                f.close()
-                if not exists and self.chmod:
-                    os.chmod(filename, self.chmod)
-
-    def _clean_up(self):
-        global cleaning_up
-        try:
-            exp_time = datetime.timedelta(seconds=self.expiration*60)
-            now = datetime.datetime.now()
-
-            #Open every session and check that it isn't too old
-            for root, dirs, files in os.walk(self.session_file_path):
-                for f in files:
-                    self._clean_up_file(f, exp_time=exp_time, now=now)
-        finally:
-            cleaning_up = False
-
-    def _clean_up_file(self, f, exp_time, now):
-        t = f.split("-")
-        if len(t) != 2:
-            return
-        t = t[0]
-        try:
-            sess_time = datetime.datetime(
-                    int(t[0:4]),
-                    int(t[4:6]),
-                    int(t[6:8]),
-                    int(t[8:10]),
-                    int(t[10:12]),
-                    int(t[12:14]))
-        except ValueError:
-            # Probably not a session file at all
-            return
-
-        if sess_time + exp_time < now:
-            os.remove(os.path.join(self.session_file_path, f))
-
-    def clean_up(self):
-        global last_cleanup, cleanup_cycle, cleaning_up
-        now = datetime.datetime.now()
-
-        if cleaning_up:
-            return
-
-        if not last_cleanup or last_cleanup + cleanup_cycle < now:
-            if not cleaning_up:
-                cleaning_up = True
-                try:
-                    last_cleanup = now
-                    t = threading.Thread(target=self._clean_up)
-                    t.start()
-                except:
-                    # Normally _clean_up should set cleaning_up
-                    # to false, but if something goes wrong starting
-                    # it...
-                    cleaning_up = False
-                    raise
-
-class _NoDefault(object):
-    def __repr__(self):
-        return '<dynamic default>'
-NoDefault = _NoDefault()
-
-def make_session_middleware(
-    app, global_conf,
-    session_expiration=NoDefault,
-    expiration=NoDefault,
-    cookie_name=NoDefault,
-    session_file_path=NoDefault,
-    chmod=NoDefault):
-    """
-    Adds a middleware that handles sessions for your applications.
-    The session is a peristent dictionary.  To get this dictionary
-    in your application, use ``environ['paste.session.factory']()``
-    which returns this persistent dictionary.
-
-    Configuration:
-
-      session_expiration:
-          The time each session lives, in minutes.  This controls
-          the cookie expiration.  Default 12 hours.
-
-      expiration:
-          The time each session lives on disk.  Old sessions are
-          culled from disk based on this.  Default 48 hours.
-
-      cookie_name:
-          The cookie name used to track the session.  Use different
-          names to avoid session clashes.
-
-      session_file_path:
-          Sessions are put in this location, default /tmp.
-
-      chmod:
-          The octal chmod you want to apply to new sessions (e.g., 660
-          to make the sessions group readable/writable)
-
-    Each of these also takes from the global configuration.  cookie_name
-    and chmod take from session_cookie_name and session_chmod
-    """
-    if session_expiration is NoDefault:
-        session_expiration = global_conf.get('session_expiration', 60*12)
-    session_expiration = int(session_expiration)
-    if expiration is NoDefault:
-        expiration = global_conf.get('expiration', 60*48)
-    expiration = int(expiration)
-    if cookie_name is NoDefault:
-        cookie_name = global_conf.get('session_cookie_name', '_SID_')
-    if session_file_path is NoDefault:
-        session_file_path = global_conf.get('session_file_path', '/tmp')
-    if chmod is NoDefault:
-        chmod = global_conf.get('session_chmod', None)
-    return SessionMiddleware(
-        app, session_expiration=session_expiration,
-        expiration=expiration, cookie_name=cookie_name,
-        session_file_path=session_file_path, chmod=chmod)
diff --git a/lib/paste/transaction.py b/lib/paste/transaction.py
@@ -1,120 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-# (c) 2005 Clark C. Evans
-# This module is part of the Python Paste Project and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-"""
-Middleware related to transactions and database connections.
-
-At this time it is very basic; but will eventually sprout all that
-two-phase commit goodness that I don't need.
-
-.. note::
-
-   This is experimental, and will change in the future.
-"""
-from paste.httpexceptions import HTTPException
-from wsgilib import catch_errors
-
-class TransactionManagerMiddleware(object):
-
-    def __init__(self, application):
-        self.application = application
-
-    def __call__(self, environ, start_response):
-        environ['paste.transaction_manager'] = manager = Manager()
-        # This makes sure nothing else traps unexpected exceptions:
-        environ['paste.throw_errors'] = True
-        return catch_errors(self.application, environ, start_response,
-                            error_callback=manager.error,
-                            ok_callback=manager.finish)
-
-class Manager(object):
-
-    def __init__(self):
-        self.aborted = False
-        self.transactions = []
-
-    def abort(self):
-        self.aborted = True
-
-    def error(self, exc_info):
-        self.aborted = True
-        self.finish()
-
-    def finish(self):
-        for trans in self.transactions:
-            if self.aborted:
-                trans.rollback()
-            else:
-                trans.commit()
-
-
-class ConnectionFactory(object):
-    """
-    Provides a callable interface for connecting to ADBAPI databases in
-    a WSGI style (using the environment).  More advanced connection
-    factories might use the REMOTE_USER and/or other environment
-    variables to make the connection returned depend upon the request.
-    """
-    def __init__(self, module, *args, **kwargs):
-        #assert getattr(module,'threadsaftey',0) > 0
-        self.module = module
-        self.args = args
-        self.kwargs = kwargs
-
-        # deal with database string quoting issues
-        self.quote = lambda s: "'%s'" % s.replace("'","''")
-        if hasattr(self.module,'PgQuoteString'):
-            self.quote = self.module.PgQuoteString
-
-    def __call__(self, environ=None):
-        conn = self.module.connect(*self.args, **self.kwargs)
-        conn.__dict__['module'] = self.module
-        conn.__dict__['quote'] = self.quote
-        return conn
-
-def BasicTransactionHandler(application, factory):
-    """
-    Provides a simple mechanism for starting a transaction based on the
-    factory; and for either committing or rolling back the transaction
-    depending on the result.  It checks for the response's current
-    status code either through the latest call to start_response; or
-    through a HTTPException's code.  If it is a 100, 200, or 300; the
-    transaction is committed; otherwise it is rolled back.
-    """
-    def basic_transaction(environ, start_response):
-        conn = factory(environ)
-        environ['paste.connection'] = conn
-        should_commit = [500]
-        def finalizer(exc_info=None):
-            if exc_info:
-                if isinstance(exc_info[1], HTTPException):
-                    should_commit.append(exc_info[1].code)
-            if should_commit.pop() < 400:
-                conn.commit()
-            else:
-                try:
-                    conn.rollback()
-                except:
-                    # TODO: check if rollback has already happened
-                    return
-            conn.close()
-        def basictrans_start_response(status, headers, exc_info = None):
-            should_commit.append(int(status.split(" ")[0]))
-            return start_response(status, headers, exc_info)
-        return catch_errors(application, environ, basictrans_start_response,
-                            finalizer, finalizer)
-    return basic_transaction
-
-__all__ = ['ConnectionFactory', 'BasicTransactionHandler']
-
-if '__main__' == __name__ and False:
-    from pyPgSQL import PgSQL
-    factory = ConnectionFactory(PgSQL, database="testing")
-    conn = factory()
-    curr = conn.cursor()
-    curr.execute("SELECT now(), %s" % conn.quote("B'n\\'gles"))
-    (time, bing) = curr.fetchone()
-    print bing, time
-
diff --git a/lib/paste/translogger.py b/lib/paste/translogger.py
@@ -1,116 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-Middleware for logging requests, using Apache combined log format
-"""
-
-import logging
-import time
-import urllib
-
-class TransLogger(object):
-    """
-    This logging middleware will log all requests as they go through.
-    They are, by default, sent to a logger named ``'wsgi'`` at the
-    INFO level.
-
-    If ``setup_console_handler`` is true, then messages for the named
-    logger will be sent to the console.
-    """
-
-    format = ('%(REMOTE_ADDR)s - %(REMOTE_USER)s [%(time)s] '
-              '"%(REQUEST_METHOD)s %(REQUEST_URI)s %(HTTP_VERSION)s" '
-              '%(status)s %(bytes)s "%(HTTP_REFERER)s" "%(HTTP_USER_AGENT)s"')
-
-    def __init__(self, application,
-                 logger=None,
-                 format=None,
-                 logging_level=logging.INFO,
-                 logger_name='wsgi',
-                 setup_console_handler=True,
-                 set_logger_level=logging.DEBUG):
-        if format is not None:
-            self.format = format
-        self.application = application
-        self.logging_level = logging_level
-        self.logger_name = logger_name
-        if logger is None:
-            self.logger = logging.getLogger(self.logger_name)
-            if setup_console_handler:
-                console = logging.StreamHandler()
-                console.setLevel(logging.DEBUG)
-                # We need to control the exact format:
-                console.setFormatter(logging.Formatter('%(message)s'))
-                self.logger.addHandler(console)
-                self.logger.propagate = False
-            if set_logger_level is not None:
-                self.logger.setLevel(set_logger_level)
-        else:
-            self.logger = logger
-
-    def __call__(self, environ, start_response):
-        start = time.localtime()
-        req_uri = urllib.quote(environ.get('SCRIPT_NAME', '')
-                               + environ.get('PATH_INFO', ''))
-        if environ.get('QUERY_STRING'):
-            req_uri += '?'+environ['QUERY_STRING']
-        method = environ['REQUEST_METHOD']
-        def replacement_start_response(status, headers, exc_info=None):
-            # @@: Ideally we would count the bytes going by if no
-            # content-length header was provided; but that does add
-            # some overhead, so at least for now we'll be lazy.
-            bytes = None
-            for name, value in headers:
-                if name.lower() == 'content-length':
-                    bytes = value
-            self.write_log(environ, method, req_uri, start, status, bytes)
-            return start_response(status, headers)
-        return self.application(environ, replacement_start_response)
-
-    def write_log(self, environ, method, req_uri, start, status, bytes):
-        if bytes is None:
-            bytes = '-'
-        if time.daylight:
-                offset = time.altzone / 60 / 60 * -100
-        else:
-                offset = time.timezone / 60 / 60 * -100
-        if offset >= 0:
-                offset = "+%0.4d" % (offset)
-        elif offset < 0:
-                offset = "%0.4d" % (offset)
-        d = {
-            'REMOTE_ADDR': environ.get('REMOTE_ADDR') or '-',
-            'REMOTE_USER': environ.get('REMOTE_USER') or '-',
-            'REQUEST_METHOD': method,
-            'REQUEST_URI': req_uri,
-            'HTTP_VERSION': environ.get('SERVER_PROTOCOL'),
-            'time': time.strftime('%d/%b/%Y:%H:%M:%S ', start) + offset,
-            'status': status.split(None, 1)[0],
-            'bytes': bytes,
-            'HTTP_REFERER': environ.get('HTTP_REFERER', '-'),
-            'HTTP_USER_AGENT': environ.get('HTTP_USER_AGENT', '-'),
-            }
-        message = self.format % d
-        self.logger.log(self.logging_level, message)
-
-def make_filter(
-    app, global_conf,
-    logger_name='wsgi',
-    format=None,
-    logging_level=logging.INFO,
-    setup_console_handler=True,
-    set_logger_level=logging.DEBUG):
-    from paste.util.converters import asbool
-    if isinstance(logging_level, basestring):
-        logging_level = logging._levelNames[logging_level]
-    if isinstance(set_logger_level, basestring):
-        set_logger_level = logging._levelNames[set_logger_level]
-    return TransLogger(
-        app,
-        format=format or None,
-        logging_level=logging_level,
-        logger_name=logger_name,
-        setup_console_handler=asbool(setup_console_handler),
-        set_logger_level=set_logger_level)
-
-make_filter.__doc__ = TransLogger.__doc__
diff --git a/lib/paste/url.py b/lib/paste/url.py
@@ -1,475 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-"""
-This module implements a class for handling URLs.
-"""
-import urllib
-import cgi
-from paste import request
-# Imported lazily from FormEncode:
-variabledecode = None
-
-__all__ = ["URL", "Image"]
-
-def html_quote(v):
-    if v is None:
-        return ''
-    return cgi.escape(str(v), 1)
-
-def url_quote(v):
-    if v is None:
-        return ''
-    return urllib.quote(str(v))
-
-url_unquote = urllib.unquote
-
-def js_repr(v):
-    if v is None:
-        return 'null'
-    elif v is False:
-        return 'false'
-    elif v is True:
-        return 'true'
-    elif isinstance(v, list):
-        return '[%s]' % ', '.join(map(js_repr, v))
-    elif isinstance(v, dict):
-        return '{%s}' % ', '.join(
-            ['%s: %s' % (js_repr(key), js_repr(value))
-             for key, value in v])
-    elif isinstance(v, str):
-        return repr(v)
-    elif isinstance(v, unicode):
-        # @@: how do you do Unicode literals in Javascript?
-        return repr(v.encode('UTF-8'))
-    elif isinstance(v, (float, int)):
-        return repr(v)
-    elif isinstance(v, long):
-        return repr(v).lstrip('L')
-    elif hasattr(v, '__js_repr__'):
-        return v.__js_repr__()
-    else:
-        raise ValueError(
-            "I don't know how to turn %r into a Javascript representation"
-            % v)
-
-class URLResource(object):
-
-    """
-    This is an abstract superclass for different kinds of URLs
-    """
-
-    default_params = {}
-
-    def __init__(self, url, vars=None, attrs=None,
-                 params=None):
-        self.url = url or '/'
-        self.vars = vars or []
-        self.attrs = attrs or {}
-        self.params = self.default_params.copy()
-        self.original_params = params or {}
-        if params:
-            self.params.update(params)
-
-    #@classmethod
-    def from_environ(cls, environ, with_query_string=True,
-                     with_path_info=True, script_name=None,
-                     path_info=None, querystring=None):
-        url = request.construct_url(
-            environ, with_query_string=False,
-            with_path_info=with_path_info, script_name=script_name,
-            path_info=path_info)
-        if with_query_string:
-            if querystring is None:
-                vars = request.parse_querystring(environ)
-            else:
-                vars = cgi.parse_qsl(
-                    querystring,
-                    keep_blank_values=True,
-                    strict_parsing=False)
-        else:
-            vars = None
-        v = cls(url, vars=vars)
-        return v
-
-    from_environ = classmethod(from_environ)
-
-    def __call__(self, *args, **kw):
-        res = self._add_positional(args)
-        res = res._add_vars(kw)
-        return res
-
-    def __getitem__(self, item):
-        if '=' in item:
-            name, value = item.split('=', 1)
-            return self._add_vars({url_unquote(name): url_unquote(value)})
-        return self._add_positional((item,))
-
-    def attr(self, **kw):
-        for key in kw.keys():
-            if key.endswith('_'):
-                kw[key[:-1]] = kw[key]
-                del kw[key]
-        new_attrs = self.attrs.copy()
-        new_attrs.update(kw)
-        return self.__class__(self.url, vars=self.vars,
-                              attrs=new_attrs,
-                              params=self.original_params)
-
-    def param(self, **kw):
-        new_params = self.original_params.copy()
-        new_params.update(kw)
-        return self.__class__(self.url, vars=self.vars,
-                              attrs=self.attrs,
-                              params=new_params)
-
-    def coerce_vars(self, vars):
-        global variabledecode
-        need_variable_encode = False
-        for key, value in vars.items():
-            if isinstance(value, dict):
-                need_variable_encode = True
-            if key.endswith('_'):
-                vars[key[:-1]] = vars[key]
-                del vars[key]
-        if need_variable_encode:
-            if variabledecode is None:
-                from formencode import variabledecode
-            vars = variabledecode.variable_encode(vars)
-        return vars
-
-    
-    def var(self, **kw):
-        kw = self.coerce_vars(kw)
-        new_vars = self.vars + kw.items()
-        return self.__class__(self.url, vars=new_vars,
-                              attrs=self.attrs,
-                              params=self.original_params)
-
-    def setvar(self, **kw):
-        """
-        Like ``.var(...)``, except overwrites keys, where .var simply
-        extends the keys.  Setting a variable to None here will
-        effectively delete it.
-        """
-        kw = self.coerce_vars(kw)
-        new_vars = []
-        for name, values in self.vars:
-            if name in kw:
-                continue
-            new_vars.append((name, values))
-        new_vars.extend(kw.items())
-        return self.__class__(self.url, vars=new_vars,
-                              attrs=self.attrs,
-                              params=self.original_params)
-
-    def setvars(self, **kw):
-        """
-        Creates a copy of this URL, but with all the variables set/reset
-        (like .setvar(), except clears past variables at the same time)
-        """
-        return self.__class__(self.url, vars=kw.items(),
-                              attrs=self.attrs,
-                              params=self.original_params)
-
-    def addpath(self, *paths):
-        u = self
-        for path in paths:
-            path = str(path).lstrip('/')
-            new_url = u.url
-            if not new_url.endswith('/'):
-                new_url += '/'
-            u = u.__class__(new_url+path, vars=u.vars,
-                            attrs=u.attrs,
-                            params=u.original_params)
-        return u
-            
-    __div__ = addpath
-
-    def become(self, OtherClass):
-        return OtherClass(self.url, vars=self.vars,
-                          attrs=self.attrs,
-                          params=self.original_params)
-    
-    def href__get(self):
-        s = self.url
-        if self.vars:
-            s += '?'
-            vars = []
-            for name, val in self.vars:
-                if isinstance(val, (list, tuple)):
-                    val = [v for v in val if v is not None]
-                elif val is None:
-                    continue
-                vars.append((name, val))
-            s += urllib.urlencode(vars, True)
-        return s
-
-    href = property(href__get)
-
-    def __repr__(self):
-        base = '<%s %s' % (self.__class__.__name__,
-                           self.href or "''")
-        if self.attrs:
-            base += ' attrs(%s)' % (
-                ' '.join(['%s="%s"' % (html_quote(n), html_quote(v))
-                          for n, v in self.attrs.items()]))
-        if self.original_params:
-            base += ' params(%s)' % (
-                ', '.join(['%s=%r' % (n, v)
-                           for n, v in self.attrs.items()]))
-        return base + '>'
-    
-    def html__get(self):
-        if not self.params.get('tag'):
-            raise ValueError(
-                "You cannot get the HTML of %r until you set the "
-                "'tag' param'" % self)
-        content = self._get_content()
-        tag = '<%s' % self.params.get('tag')
-        attrs = ' '.join([
-            '%s="%s"' % (html_quote(n), html_quote(v))
-            for n, v in self._html_attrs()])
-        if attrs:
-            tag += ' ' + attrs
-        tag += self._html_extra()
-        if content is None:
-            return tag + ' />'
-        else:
-            return '%s>%s</%s>' % (tag, content, self.params.get('tag'))
-
-    html = property(html__get)
-
-    def _html_attrs(self):
-        return self.attrs.items()
-
-    def _html_extra(self):
-        return ''
-
-    def _get_content(self):
-        """
-        Return the content for a tag (for self.html); return None
-        for an empty tag (like ``<img />``)
-        """
-        raise NotImplementedError
-    
-    def _add_vars(self, vars):
-        raise NotImplementedError
-
-    def _add_positional(self, args):
-        raise NotImplementedError
-
-class URL(URLResource):
-
-    r"""
-    >>> u = URL('http://localhost')
-    >>> u
-    <URL http://localhost>
-    >>> u = u['view']
-    >>> str(u)
-    'http://localhost/view'
-    >>> u['//foo'].param(content='view').html
-    '<a href="http://localhost/view/foo">view</a>'
-    >>> u.param(confirm='Really?', content='goto').html
-    '<a href="http://localhost/view" onclick="return confirm(\'Really?\')">goto</a>'
-    >>> u(title='See "it"', content='goto').html
-    '<a href="http://localhost/view?title=See+%22it%22">goto</a>'
-    >>> u('another', var='fuggetaboutit', content='goto').html
-    '<a href="http://localhost/view/another?var=fuggetaboutit">goto</a>'
-    >>> u.attr(content='goto').html
-    Traceback (most recent call last):
-        ....
-    ValueError: You must give a content param to <URL http://localhost/view attrs(content="goto")> generate anchor tags
-    >>> str(u['foo=bar%20stuff'])
-    'http://localhost/view?foo=bar+stuff'
-    """
-
-    default_params = {'tag': 'a'}
-
-    def __str__(self):
-        return self.href
-
-    def _get_content(self):
-        if not self.params.get('content'):
-            raise ValueError(
-                "You must give a content param to %r generate anchor tags"
-                % self)
-        return self.params['content']
-
-    def _add_vars(self, vars):
-        url = self
-        for name in ('confirm', 'content'):
-            if name in vars:
-                url = url.param(**{name: vars.pop(name)})
-        if 'target' in vars:
-            url = url.attr(target=vars.pop('target'))
-        return url.var(**vars)
-
-    def _add_positional(self, args):
-        return self.addpath(*args)
-
-    def _html_attrs(self):
-        attrs = self.attrs.items()
-        attrs.insert(0, ('href', self.href))
-        if self.params.get('confirm'):
-            attrs.append(('onclick', 'return confirm(%s)'
-                          % js_repr(self.params['confirm'])))
-        return attrs
-
-    def onclick_goto__get(self):
-        return 'location.href=%s; return false' % js_repr(self.href)
-
-    onclick_goto = property(onclick_goto__get)
-
-    def button__get(self):
-        return self.become(Button)
-
-    button = property(button__get)
-
-    def js_popup__get(self):
-        return self.become(JSPopup)
-
-    js_popup = property(js_popup__get)
-            
-class Image(URLResource):
-
-    r"""
-    >>> i = Image('/images')
-    >>> i = i / '/foo.png'
-    >>> i.html
-    '<img src="/images/foo.png" />'
-    >>> str(i['alt=foo'])
-    '<img src="/images/foo.png" alt="foo" />'
-    >>> i.href
-    '/images/foo.png'
-    """
-    
-    default_params = {'tag': 'img'}
-
-    def __str__(self):
-        return self.html
-
-    def _get_content(self):
-        return None
-
-    def _add_vars(self, vars):
-        return self.attr(**vars)
-
-    def _add_positional(self, args):
-        return self.addpath(*args)
-
-    def _html_attrs(self):
-        attrs = self.attrs.items()
-        attrs.insert(0, ('src', self.href))
-        return attrs
-
-class Button(URLResource):
-
-    r"""
-    >>> u = URL('/')
-    >>> u = u / 'delete'
-    >>> b = u.button['confirm=Sure?'](id=5, content='del')
-    >>> str(b)
-    '<button onclick="if (confirm(\'Sure?\')) {location.href=\'/delete?id=5\'}; return false">del</button>'
-    """
-
-    default_params = {'tag': 'button'}
-
-    def __str__(self):
-        return self.html
-
-    def _get_content(self):
-        if self.params.get('content'):
-            return self.params['content']
-        if self.attrs.get('value'):
-            return self.attrs['content']
-        # @@: Error?
-        return None
-
-    def _add_vars(self, vars):
-        button = self
-        if 'confirm' in vars:
-            button = button.param(confirm=vars.pop('confirm'))
-        if 'content' in vars:
-            button = button.param(content=vars.pop('content'))
-        return button.var(**vars)
-
-    def _add_positional(self, args):
-        return self.addpath(*args)
-
-    def _html_attrs(self):
-        attrs = self.attrs.items()
-        onclick = 'location.href=%s' % js_repr(self.href)
-        if self.params.get('confirm'):
-            onclick = 'if (confirm(%s)) {%s}' % (
-                js_repr(self.params['confirm']), onclick)
-        onclick += '; return false'
-        attrs.insert(0, ('onclick', onclick))
-        return attrs
-
-class JSPopup(URLResource):
-
-    r"""
-    >>> u = URL('/')
-    >>> u = u / 'view'
-    >>> j = u.js_popup(content='view')
-    >>> j.html
-    '<a href="/view" onclick="window.open(\'/view\', \'_blank\'); return false" target="_blank">view</a>'
-    """
-
-    default_params = {'tag': 'a', 'target': '_blank'}
-
-    def _add_vars(self, vars):
-        button = self
-        for var in ('width', 'height', 'stripped', 'content'):
-            if var in vars:
-                button = button.param(**{var: vars.pop(var)})
-        return button.var(**vars)
-
-    def _window_args(self):
-        p = self.params
-        features = []
-        if p.get('stripped'):
-            p['location'] = p['status'] = p['toolbar'] = '0'
-        for param in 'channelmode directories fullscreen location menubar resizable scrollbars status titlebar'.split():
-            if param not in p:
-                continue
-            v = p[param]
-            if v not in ('yes', 'no', '1', '0'):
-                if v:
-                    v = '1'
-                else:
-                    v = '0'
-            features.append('%s=%s' % (param, v))
-        for param in 'height left top width':
-            if not p.get(param):
-                continue
-            features.append('%s=%s' % (param, p[param]))
-        args = [self.href, p['target']]
-        if features:
-            args.append(','.join(features))
-        return ', '.join(map(js_repr, args))
-
-    def _html_attrs(self):
-        attrs = self.attrs.items()
-        onclick = ('window.open(%s); return false'
-                   % self._window_args())
-        attrs.insert(0, ('target', self.params['target']))
-        attrs.insert(0, ('onclick', onclick))
-        attrs.insert(0, ('href', self.href))
-        return attrs
-
-    def _get_content(self):
-        if not self.params.get('content'):
-            raise ValueError(
-                "You must give a content param to %r generate anchor tags"
-                % self)
-        return self.params['content']
-
-    def _add_positional(self, args):
-        return self.addpath(*args)
-
-if __name__ == '__main__':
-    import doctest
-    doctest.testmod()
-    
diff --git a/lib/paste/urlmap.py b/lib/paste/urlmap.py
@@ -1,251 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-Map URL prefixes to WSGI applications.  See ``URLMap``
-"""
-
-from UserDict import DictMixin
-import re
-import os
-from paste import httpexceptions
-
-__all__ = ['URLMap', 'PathProxyURLMap']
-
-def urlmap_factory(loader, global_conf, **local_conf):
-    if 'not_found_app' in local_conf:
-        not_found_app = local_conf.pop('not_found_app')
-    else:
-        not_found_app = global_conf.get('not_found_app')
-    if not_found_app:
-        not_found_app = loader.get_app(not_found_app, global_conf=global_conf)
-    urlmap = URLMap(not_found_app=not_found_app)
-    for path, app_name in local_conf.items():
-        path = parse_path_expression(path)
-        app = loader.get_app(app_name, global_conf=global_conf)
-        urlmap[path] = app
-    return urlmap
-
-def parse_path_expression(path):
-    """
-    Parses a path expression like 'domain foobar.com port 20 /' or
-    just '/foobar' for a path alone.  Returns as an address that
-    URLMap likes.
-    """
-    parts = path.split()
-    domain = port = path = None
-    while parts:
-        if parts[0] == 'domain':
-            parts.pop(0)
-            if not parts:
-                raise ValueError("'domain' must be followed with a domain name")
-            if domain:
-                raise ValueError("'domain' given twice")
-            domain = parts.pop(0)
-        elif parts[0] == 'port':
-            parts.pop(0)
-            if not parts:
-                raise ValueError("'port' must be followed with a port number")
-            if port:
-                raise ValueError("'port' given twice")
-            port = parts.pop(0)
-        else:
-            if path:
-                raise ValueError("more than one path given (have %r, got %r)"
-                                 % (path, parts[0]))
-            path = parts.pop(0)
-    s = ''
-    if domain:
-        s = 'http://%s' % domain
-    if port:
-        if not domain:
-            raise ValueError("If you give a port, you must also give a domain")
-        s += ':' + port
-    if path:
-        if s:
-            s += '/'
-        s += path
-    return s
-
-class URLMap(DictMixin):
-
-    """
-    URLMap instances are dictionary-like object that dispatch to one
-    of several applications based on the URL.
-
-    The dictionary keys are URLs to match (like
-    ``PATH_INFO.startswith(url)``), and the values are applications to
-    dispatch to.  URLs are matched most-specific-first, i.e., longest
-    URL first.  The ``SCRIPT_NAME`` and ``PATH_INFO`` environmental
-    variables are adjusted to indicate the new context.
-    
-    URLs can also include domains, like ``http://blah.com/foo``, or as
-    tuples ``('blah.com', '/foo')``.  This will match domain names; without
-    the ``http://domain`` or with a domain of ``None`` any domain will be
-    matched (so long as no other explicit domain matches).  """
-    
-    def __init__(self, not_found_app=None):
-        self.applications = []
-        if not not_found_app:
-            not_found_app = self.not_found_app
-        self.not_found_application = not_found_app
-
-    norm_url_re = re.compile('//+')
-    domain_url_re = re.compile('^(http|https)://')
-
-    def not_found_app(self, environ, start_response):
-        mapper = environ.get('paste.urlmap_object')
-        if mapper:
-            matches = [p for p, a in mapper.applications]
-            extra = 'defined apps: %s' % (
-                ',\n  '.join(map(repr, matches)))
-        else:
-            extra = ''
-        extra += '\nSCRIPT_NAME: %r' % environ.get('SCRIPT_NAME')
-        extra += '\nPATH_INFO: %r' % environ.get('PATH_INFO')
-        extra += '\nHTTP_HOST: %r' % environ.get('HTTP_HOST')
-        app = httpexceptions.HTTPNotFound(
-            environ['PATH_INFO'],
-            comment=extra).wsgi_application
-        return app(environ, start_response)
-
-    def normalize_url(self, url, trim=True):
-        if isinstance(url, (list, tuple)):
-            domain = url[0]
-            url = self.normalize_url(url[1])[1]
-            return domain, url
-        assert (not url or url.startswith('/') 
-                or self.domain_url_re.search(url)), (
-            "URL fragments must start with / or http:// (you gave %r)" % url)
-        match = self.domain_url_re.search(url)
-        if match:
-            url = url[match.end():]
-            if '/' in url:
-                domain, url = url.split('/', 1)
-                url = '/' + url
-            else:
-                domain, url = url, ''
-        else:
-            domain = None
-        url = self.norm_url_re.sub('/', url)
-        if trim:
-            url = url.rstrip('/')
-        return domain, url
-
-    def sort_apps(self):
-        """
-        Make sure applications are sorted with longest URLs first
-        """
-        def key(app_desc):
-            (domain, url), app = app_desc
-            if not domain:
-                # Make sure empty domains sort last:
-                return '\xff', -len(url)
-            else:
-                return domain, -len(url)
-        apps = [(key(desc), desc) for desc in self.applications]
-        apps.sort()
-        self.applications = [desc for (sortable, desc) in apps]
-
-    def __setitem__(self, url, app):
-        if app is None:
-            try:
-                del self[url]
-            except KeyError:
-                pass
-            return
-        dom_url = self.normalize_url(url)
-        if dom_url in self:
-            del self[dom_url]
-        self.applications.append((dom_url, app))
-        self.sort_apps()
-
-    def __getitem__(self, url):
-        dom_url = self.normalize_url(url)
-        for app_url, app in self.applications:
-            if app_url == dom_url:
-                return app
-        raise KeyError(
-            "No application with the url %r (domain: %r; existing: %s)" 
-            % (url[1], url[0] or '*', self.applications))
-
-    def __delitem__(self, url):
-        url = self.normalize_url(url)
-        for app_url, app in self.applications:
-            if app_url == url:
-                self.applications.remove((app_url, app))
-                break
-        else:
-            raise KeyError(
-                "No application with the url %r" % (url,))
-
-    def keys(self):
-        return [app_url for app_url, app in self.applications]
-
-    def __call__(self, environ, start_response):
-        host = environ.get('HTTP_HOST', environ.get('SERVER_NAME')).lower()
-        if ':' in host:
-            host, port = host.split(':', 1)
-        else:
-            if environ['wsgi.url_scheme'] == 'http':
-                port = '80'
-            else:
-                port = '443'
-        path_info = environ.get('PATH_INFO')
-        path_info = self.normalize_url(path_info, False)[1]
-        for (domain, app_url), app in self.applications:
-            if domain and domain != host and domain != host+':'+port:
-                continue
-            if (path_info == app_url
-                or path_info.startswith(app_url + '/')):
-                environ['SCRIPT_NAME'] += app_url
-                environ['PATH_INFO'] = path_info[len(app_url):]
-                return app(environ, start_response)
-        environ['paste.urlmap_object'] = self
-        return self.not_found_application(environ, start_response)
-    
-            
-class PathProxyURLMap(object):
-
-    """
-    This is a wrapper for URLMap that catches any strings that
-    are passed in as applications; these strings are treated as
-    filenames (relative to `base_path`) and are passed to the
-    callable `builder`, which will return an application.
-
-    This is intended for cases when configuration files can be
-    treated as applications.
-
-    `base_paste_url` is the URL under which all applications added through
-    this wrapper must go.  Use ``""`` if you want this to not
-    change incoming URLs.
-    """
-
-    def __init__(self, map, base_paste_url, base_path, builder):
-        self.map = map
-        self.base_paste_url = self.map.normalize_url(base_paste_url)
-        self.base_path = base_path
-        self.builder = builder
-        
-    def __setitem__(self, url, app):
-        if isinstance(app, (str, unicode)):
-            app_fn = os.path.join(self.base_path, app)
-            app = self.builder(app_fn)
-        url = self.map.normalize_url(url)
-        # @@: This means http://foo.com/bar will potentially
-        # match foo.com, but /base_paste_url/bar, which is unintuitive
-        url = (url[0] or self.base_paste_url[0], 
-               self.base_paste_url[1] + url[1])
-        self.map[url] = app
-
-    def __getattr__(self, attr):
-        return getattr(self.map, attr)
-
-    # This is really the only settable attribute
-    def not_found_application__get(self):
-        return self.map.not_found_application
-    def not_found_application__set(self, value):
-        self.map.not_found_application = value
-    not_found_application = property(not_found_application__get,
-                                     not_found_application__set)
-        
-    
diff --git a/lib/paste/urlparser.py b/lib/paste/urlparser.py
@@ -1,652 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-WSGI applications that parse the URL and dispatch to on-disk resources
-"""
-
-import os
-import sys
-import imp
-import mimetypes
-try:
-    import pkg_resources
-except ImportError:
-    pkg_resources = None
-from paste import request
-from paste import fileapp
-from paste.util import import_string
-from paste import httpexceptions
-from httpheaders import ETAG
-from paste.util import converters
-
-class NoDefault(object):
-    pass
-
-__all__ = ['URLParser', 'StaticURLParser', 'PkgResourcesParser']
-
-class URLParser(object):
-
-    """
-    WSGI middleware
-
-    Application dispatching, based on URL.  An instance of `URLParser` is
-    an application that loads and delegates to other applications.  It
-    looks for files in its directory that match the first part of
-    PATH_INFO; these may have an extension, but are not required to have
-    one, in which case the available files are searched to find the
-    appropriate file.  If it is ambiguous, a 404 is returned and an error
-    logged.
-
-    By default there is a constructor for .py files that loads the module,
-    and looks for an attribute ``application``, which is a ready
-    application object, or an attribute that matches the module name,
-    which is a factory for building applications, and is called with no
-    arguments.
-
-    URLParser will also look in __init__.py for special overrides.
-    These overrides are:
-
-    ``urlparser_hook(environ)``
-        This can modify the environment.  Its return value is ignored,
-        and it cannot be used to change the response in any way.  You
-        *can* use this, for example, to manipulate SCRIPT_NAME/PATH_INFO
-        (try to keep them consistent with the original URL -- but
-        consuming PATH_INFO and moving that to SCRIPT_NAME is ok).
-
-    ``urlparser_wrap(environ, start_response, app)``:
-        After URLParser finds the application, it calls this function
-        (if present).  If this function doesn't call
-        ``app(environ, start_response)`` then the application won't be
-        called at all!  This can be used to allocate resources (with
-        ``try:finally:``) or otherwise filter the output of the
-        application.
-
-    ``not_found_hook(environ, start_response)``:
-        If no file can be found (*in this directory*) to match the
-        request, then this WSGI application will be called.  You can
-        use this to change the URL and pass the request back to
-        URLParser again, or on to some other application.  This
-        doesn't catch all ``404 Not Found`` responses, just missing
-        files.
-
-    ``application(environ, start_response)``:
-        This basically overrides URLParser completely, and the given
-        application is used for all requests.  ``urlparser_wrap`` and
-        ``urlparser_hook`` are still called, but the filesystem isn't
-        searched in any way.
-    """
-
-    parsers_by_directory = {}
-
-    # This is lazily initialized
-    init_module = NoDefault
-
-    global_constructors = {}
-
-    def __init__(self, global_conf,
-                 directory, base_python_name,
-                 index_names=NoDefault,
-                 hide_extensions=NoDefault,
-                 ignore_extensions=NoDefault,
-                 constructors=None,
-                 **constructor_conf):
-        """
-        Create a URLParser object that looks at `directory`.
-        `base_python_name` is the package that this directory
-        represents, thus any Python modules in this directory will
-        be given names under this package.
-        """
-        if global_conf:
-            import warnings
-            warnings.warn(
-                'The global_conf argument to URLParser is deprecated; '
-                'either pass in None or {}, or use make_url_parser',
-                DeprecationWarning)
-        else:
-            global_conf = {}
-        if os.path.sep != '/':
-            directory = directory.replace(os.path.sep, '/')
-        self.directory = directory
-        self.base_python_name = base_python_name
-        # This logic here should be deprecated since it is in
-        # make_url_parser
-        if index_names is NoDefault:
-            index_names = global_conf.get(
-                'index_names', ('index', 'Index', 'main', 'Main'))
-        self.index_names = converters.aslist(index_names)
-        if hide_extensions is NoDefault:
-            hide_extensions = global_conf.get(
-                'hide_extensions', ('.pyc', '.bak', '.py~', '.pyo'))
-        self.hide_extensions = converters.aslist(hide_extensions)
-        if ignore_extensions is NoDefault:
-            ignore_extensions = global_conf.get(
-                'ignore_extensions', ())
-        self.ignore_extensions = converters.aslist(ignore_extensions)
-        self.constructors = self.global_constructors.copy()
-        if constructors:
-            self.constructors.update(constructors)
-        # @@: Should we also check the global options for constructors?
-        for name, value in constructor_conf.items():
-            if not name.startswith('constructor '):
-                raise ValueError(
-                    "Only extra configuration keys allowed are "
-                    "'constructor .ext = import_expr'; you gave %r "
-                    "(=%r)" % (name, value))
-            ext = name[len('constructor '):].strip()
-            if isinstance(value, (str, unicode)):
-                value = import_string.eval_import(value)
-            self.constructors[ext] = value
-
-    def __call__(self, environ, start_response):
-        environ['paste.urlparser.base_python_name'] = self.base_python_name
-        if self.init_module is NoDefault:
-            self.init_module = self.find_init_module(environ)
-        path_info = environ.get('PATH_INFO', '')
-        if not path_info:
-            return self.add_slash(environ, start_response)
-        if (self.init_module
-            and getattr(self.init_module, 'urlparser_hook', None)):
-            self.init_module.urlparser_hook(environ)
-        orig_path_info = environ['PATH_INFO']
-        orig_script_name = environ['SCRIPT_NAME']
-        application, filename = self.find_application(environ)
-        if not application:
-            if (self.init_module
-                and getattr(self.init_module, 'not_found_hook', None)
-                and environ.get('paste.urlparser.not_found_parser') is not self):
-                not_found_hook = self.init_module.not_found_hook
-                environ['paste.urlparser.not_found_parser'] = self
-                environ['PATH_INFO'] = orig_path_info
-                environ['SCRIPT_NAME'] = orig_script_name
-                return not_found_hook(environ, start_response)
-            if filename is None:
-                name, rest_of_path = request.path_info_split(environ['PATH_INFO'])
-                if not name:
-                    name = 'one of %s' % ', '.join(
-                        self.index_names or
-                        ['(no index_names defined)'])
-
-                return self.not_found(
-                    environ, start_response,
-                    'Tried to load %s from directory %s'
-                    % (name, self.directory))
-            else:
-                environ['wsgi.errors'].write(
-                    'Found resource %s, but could not construct application\n'
-                    % filename)
-                return self.not_found(
-                    environ, start_response,
-                    'Tried to load %s from directory %s'
-                    % (filename, self.directory))
-        if (self.init_module
-            and getattr(self.init_module, 'urlparser_wrap', None)):
-            return self.init_module.urlparser_wrap(
-                environ, start_response, application)
-        else:
-            return application(environ, start_response)
-
-    def find_application(self, environ):
-        if (self.init_module
-            and getattr(self.init_module, 'application', None)
-            and not environ.get('paste.urlparser.init_application') == environ['SCRIPT_NAME']):
-            environ['paste.urlparser.init_application'] = environ['SCRIPT_NAME']
-            return self.init_module.application, None
-        name, rest_of_path = request.path_info_split(environ['PATH_INFO'])
-        environ['PATH_INFO'] = rest_of_path
-        if name is not None:
-            environ['SCRIPT_NAME'] = environ.get('SCRIPT_NAME', '') + '/' + name
-        if not name:
-            names = self.index_names
-            for index_name in names:
-                filename = self.find_file(environ, index_name)
-                if filename:
-                    break
-            else:
-                # None of the index files found
-                filename = None
-        else:
-            filename = self.find_file(environ, name)
-        if filename is None:
-            return None, filename
-        else:
-            return self.get_application(environ, filename), filename
-
-    def not_found(self, environ, start_response, debug_message=None):
-        exc = httpexceptions.HTTPNotFound(
-            'The resource at %s could not be found'
-            % request.construct_url(environ),
-            comment='SCRIPT_NAME=%r; PATH_INFO=%r; looking in %r; debug: %s'
-            % (environ.get('SCRIPT_NAME'), environ.get('PATH_INFO'),
-               self.directory, debug_message or '(none)'))
-        return exc.wsgi_application(environ, start_response)
-
-    def add_slash(self, environ, start_response):
-        """
-        This happens when you try to get to a directory
-        without a trailing /
-        """
-        url = request.construct_url(environ, with_query_string=False)
-        url += '/'
-        if environ.get('QUERY_STRING'):
-            url += '?' + environ['QUERY_STRING']
-        exc = httpexceptions.HTTPMovedPermanently(
-            'The resource has moved to %s - you should be redirected '
-            'automatically.' % url,
-            headers=[('location', url)])
-        return exc.wsgi_application(environ, start_response)
-
-    def find_file(self, environ, base_filename):
-        possible = []
-        """Cache a few values to reduce function call overhead"""
-        for filename in os.listdir(self.directory):
-            base, ext = os.path.splitext(filename)
-            full_filename = os.path.join(self.directory, filename)
-            if (ext in self.hide_extensions
-                or not base):
-                continue
-            if filename == base_filename:
-                possible.append(full_filename)
-                continue
-            if ext in self.ignore_extensions:
-                continue
-            if base == base_filename:
-                possible.append(full_filename)
-        if not possible:
-            #environ['wsgi.errors'].write(
-            #    'No file found matching %r in %s\n'
-            #    % (base_filename, self.directory))
-            return None
-        if len(possible) > 1:
-            # If there is an exact match, this isn't 'ambiguous'
-            # per se; it might mean foo.gif and foo.gif.back for
-            # instance
-            if full_filename in possible:
-                return full_filename
-            else:
-                environ['wsgi.errors'].write(
-                    'Ambiguous URL: %s; matches files %s\n'
-                    % (request.construct_url(environ),
-                       ', '.join(possible)))
-            return None
-        return possible[0]
-
-    def get_application(self, environ, filename):
-        if os.path.isdir(filename):
-            t = 'dir'
-        else:
-            t = os.path.splitext(filename)[1]
-        constructor = self.constructors.get(t, self.constructors.get('*'))
-        if constructor is None:
-            #environ['wsgi.errors'].write(
-            #    'No constructor found for %s\n' % t)
-            return constructor
-        app = constructor(self, environ, filename)
-        if app is None:
-            #environ['wsgi.errors'].write(
-            #    'Constructor %s return None for %s\n' %
-            #    (constructor, filename))
-            pass
-        return app
-
-    def register_constructor(cls, extension, constructor):
-        """
-        Register a function as a constructor.  Registered constructors
-        apply to all instances of `URLParser`.
-
-        The extension should have a leading ``.``, or the special
-        extensions ``dir`` (for directories) and ``*`` (a catch-all).
-
-        `constructor` must be a callable that takes two arguments:
-        ``environ`` and ``filename``, and returns a WSGI application.
-        """
-        d = cls.global_constructors
-        assert not d.has_key(extension), (
-            "A constructor already exists for the extension %r (%r) "
-            "when attemption to register constructor %r"
-            % (extension, d[extension], constructor))
-        d[extension] = constructor
-    register_constructor = classmethod(register_constructor)
-
-    def get_parser(self, directory, base_python_name):
-        """
-        Get a parser for the given directory, or create one if
-        necessary.  This way parsers can be cached and reused.
-
-        # @@: settings are inherited from the first caller
-        """
-        try:
-            return self.parsers_by_directory[(directory, base_python_name)]
-        except KeyError:
-            parser = self.__class__(
-                {},
-                directory, base_python_name,
-                index_names=self.index_names,
-                hide_extensions=self.hide_extensions,
-                ignore_extensions=self.ignore_extensions,
-                constructors=self.constructors)
-            self.parsers_by_directory[(directory, base_python_name)] = parser
-            return parser
-
-    def find_init_module(self, environ):
-        filename = os.path.join(self.directory, '__init__.py')
-        if not os.path.exists(filename):
-            return None
-        return load_module(environ, filename)
-
-    def __repr__(self):
-        return '<%s directory=%r; module=%s at %s>' % (
-            self.__class__.__name__,
-            self.directory,
-            self.base_python_name,
-            hex(abs(id(self))))
-
-def make_directory(parser, environ, filename):
-    base_python_name = environ['paste.urlparser.base_python_name']
-    if base_python_name:
-        base_python_name += "." + os.path.basename(filename)
-    else:
-        base_python_name = os.path.basename(filename)
-    return parser.get_parser(filename, base_python_name)
-
-URLParser.register_constructor('dir', make_directory)
-
-def make_unknown(parser, environ, filename):
-    return fileapp.FileApp(filename)
-
-URLParser.register_constructor('*', make_unknown)
-
-def load_module(environ, filename):
-    base_python_name = environ['paste.urlparser.base_python_name']
-    module_name = os.path.splitext(os.path.basename(filename))[0]
-    if base_python_name:
-        module_name = base_python_name + '.' + module_name
-    return load_module_from_name(environ, filename, module_name,
-                                 environ['wsgi.errors'])
-
-def load_module_from_name(environ, filename, module_name, errors):
-    if sys.modules.has_key(module_name):
-        return sys.modules[module_name]
-    init_filename = os.path.join(os.path.dirname(filename), '__init__.py')
-    if not os.path.exists(init_filename):
-        try:
-            f = open(init_filename, 'w')
-        except (OSError, IOError), e:
-            errors.write(
-                'Cannot write __init__.py file into directory %s (%s)\n'
-                % (os.path.dirname(filename), e))
-            return None
-        f.write('#\n')
-        f.close()
-    fp = None
-    if sys.modules.has_key(module_name):
-        return sys.modules[module_name]
-    if '.' in module_name:
-        parent_name = '.'.join(module_name.split('.')[:-1])
-        base_name = module_name.split('.')[-1]
-        parent = load_module_from_name(environ, os.path.dirname(filename),
-                                       parent_name, errors)
-    else:
-        base_name = module_name
-    fp = None
-    try:
-        fp, pathname, stuff = imp.find_module(
-            base_name, [os.path.dirname(filename)])
-        module = imp.load_module(module_name, fp, pathname, stuff)
-    finally:
-        if fp is not None:
-            fp.close()
-    return module
-
-def make_py(parser, environ, filename):
-    module = load_module(environ, filename)
-    if not module:
-        return None
-    if hasattr(module, 'application') and module.application:
-        return getattr(module.application, 'wsgi_application', module.application)
-    base_name = module.__name__.split('.')[-1]
-    if hasattr(module, base_name):
-        obj = getattr(module, base_name)
-        if hasattr(obj, 'wsgi_application'):
-            return obj.wsgi_application
-        else:
-            # @@: Old behavior; should probably be deprecated eventually:
-            return getattr(module, base_name)()
-    environ['wsgi.errors'].write(
-        "Cound not find application or %s in %s\n"
-        % (base_name, module))
-    return None
-
-URLParser.register_constructor('.py', make_py)
-
-class StaticURLParser(object):
-    
-    """
-    Like ``URLParser`` but only serves static files.
-
-    ``cache_max_age``:
-      integer specifies Cache-Control max_age in seconds
-    """
-    # @@: Should URLParser subclass from this?
-
-    def __init__(self, directory, root_directory=None,
-                 cache_max_age=None):
-        if os.path.sep != '/':
-            directory = directory.replace(os.path.sep, '/')
-        self.directory = os.path.normcase(os.path.abspath(directory))
-        self.root_directory = root_directory
-        if root_directory is not None:
-            self.root_directory = os.path.normpath(self.root_directory)
-        else:
-            self.root_directory = directory
-        self.root_directory = os.path.normcase(os.path.normpath(
-            os.path.abspath(self.root_directory)))
-        self.cache_max_age = cache_max_age
-        if os.path.sep != '/':
-            directory = directory.replace('/', os.path.sep)
-            self.root_directory = self.root_directory.replace('/', os.path.sep)
-
-    def __call__(self, environ, start_response):
-        path_info = environ.get('PATH_INFO', '')
-        if not path_info:
-            return self.add_slash(environ, start_response)
-        if path_info == '/':
-            # @@: This should obviously be configurable
-            filename = 'index.html'
-        else:
-            filename = request.path_info_pop(environ)
-        full = os.path.normcase(os.path.normpath(
-            os.path.join(self.directory, filename)))
-        if os.path.sep != '/':
-            full = full.replace('/', os.path.sep)
-        if self.root_directory is not None and not full.startswith(self.root_directory):
-            # Out of bounds
-            return self.not_found(environ, start_response)
-        if not os.path.exists(full):
-            return self.not_found(environ, start_response)
-        if os.path.isdir(full):
-            # @@: Cache?
-            child_root = self.root_directory is not None and \
-                self.root_directory or self.directory
-            return self.__class__(full, root_directory=child_root, 
-                                  cache_max_age=self.cache_max_age)(environ,
-                                                                   start_response)
-        if environ.get('PATH_INFO') and environ.get('PATH_INFO') != '/':
-            return self.error_extra_path(environ, start_response)
-        if_none_match = environ.get('HTTP_IF_NONE_MATCH')
-        if if_none_match:
-            mytime = os.stat(full).st_mtime
-            if str(mytime) == if_none_match:
-                headers = []
-                ETAG.update(headers, mytime)
-                start_response('304 Not Modified', headers)
-                return [''] # empty body
-        
-        fa = self.make_app(full)
-        if self.cache_max_age:
-            fa.cache_control(max_age=self.cache_max_age)
-        return fa(environ, start_response)
-
-    def make_app(self, filename):
-        return fileapp.FileApp(filename)
-
-    def add_slash(self, environ, start_response):
-        """
-        This happens when you try to get to a directory
-        without a trailing /
-        """
-        url = request.construct_url(environ, with_query_string=False)
-        url += '/'
-        if environ.get('QUERY_STRING'):
-            url += '?' + environ['QUERY_STRING']
-        exc = httpexceptions.HTTPMovedPermanently(
-            'The resource has moved to %s - you should be redirected '
-            'automatically.' % url,
-            headers=[('location', url)])
-        return exc.wsgi_application(environ, start_response)
-        
-    def not_found(self, environ, start_response, debug_message=None):
-        exc = httpexceptions.HTTPNotFound(
-            'The resource at %s could not be found'
-            % request.construct_url(environ),
-            comment='SCRIPT_NAME=%r; PATH_INFO=%r; looking in %r; debug: %s'
-            % (environ.get('SCRIPT_NAME'), environ.get('PATH_INFO'),
-               self.directory, debug_message or '(none)'))
-        return exc.wsgi_application(environ, start_response)
-
-    def error_extra_path(self, environ, start_response):
-        exc = httpexceptions.HTTPNotFound(
-            'The trailing path %r is not allowed' % environ['PATH_INFO'])
-        return exc.wsgi_application(environ, start_response)
-    
-    def __repr__(self):
-        return '<%s %r>' % (self.__class__.__name__, self.directory)
-
-def make_static(global_conf, document_root, cache_max_age=None):
-    """
-    Return a WSGI application that serves a directory (configured
-    with document_root)
-    
-    cache_max_age - integer specifies CACHE_CONTROL max_age in seconds
-    """
-    if cache_max_age is not None:
-        cache_max_age = int(cache_max_age)
-    return StaticURLParser(
-        document_root, cache_max_age=cache_max_age)
-
-class PkgResourcesParser(StaticURLParser):
-
-    def __init__(self, egg_or_spec, resource_name, manager=None, root_resource=None):
-        if pkg_resources is None:
-            raise NotImplementedError("This class requires pkg_resources.")
-        if isinstance(egg_or_spec, (str, unicode)):
-            self.egg = pkg_resources.get_distribution(egg_or_spec)
-        else:
-            self.egg = egg_or_spec
-        self.resource_name = resource_name
-        if manager is None:
-            manager = pkg_resources.ResourceManager()
-        self.manager = manager
-        if root_resource is None:
-            root_resource = resource_name
-        self.root_resource = os.path.normpath(root_resource)
-
-    def __repr__(self):
-        return '<%s for %s:%r>' % (
-            self.__class__.__name__,
-            self.egg.project_name,
-            self.resource_name)
-
-    def __call__(self, environ, start_response):
-        path_info = environ.get('PATH_INFO', '')
-        if not path_info:
-            return self.add_slash(environ, start_response)
-        if path_info == '/':
-            # @@: This should obviously be configurable
-            filename = 'index.html'
-        else:
-            filename = request.path_info_pop(environ)
-        resource = os.path.normcase(os.path.normpath(
-                    self.resource_name + '/' + filename))
-        if self.root_resource is not None and not resource.startswith(self.root_resource):
-            # Out of bounds
-            return self.not_found(environ, start_response)
-        if not self.egg.has_resource(resource):
-            return self.not_found(environ, start_response)
-        if self.egg.resource_isdir(resource):
-            # @@: Cache?
-            child_root = self.root_resource is not None and self.root_resource or \
-                self.resource_name
-            return self.__class__(self.egg, resource, self.manager,
-                                  root_resource=child_root)(environ, start_response)
-        if environ.get('PATH_INFO') and environ.get('PATH_INFO') != '/':
-            return self.error_extra_path(environ, start_response)
-        
-        type, encoding = mimetypes.guess_type(resource)
-        if not type:
-            type = 'application/octet-stream'
-        # @@: I don't know what to do with the encoding.
-        try:
-            file = self.egg.get_resource_stream(self.manager, resource)
-        except (IOError, OSError), e:
-            exc = httpexceptions.HTTPForbidden(
-                'You are not permitted to view this file (%s)' % e)
-            return exc.wsgi_application(environ, start_response)
-        start_response('200 OK',
-                       [('content-type', type)])
-        return fileapp._FileIter(file)
-        
-    def not_found(self, environ, start_response, debug_message=None):
-        exc = httpexceptions.HTTPNotFound(
-            'The resource at %s could not be found'
-            % request.construct_url(environ),
-            comment='SCRIPT_NAME=%r; PATH_INFO=%r; looking in egg:%s#%r; debug: %s'
-            % (environ.get('SCRIPT_NAME'), environ.get('PATH_INFO'),
-               self.egg, self.resource_name, debug_message or '(none)'))
-        return exc.wsgi_application(environ, start_response)
-
-def make_pkg_resources(global_conf, egg, resource_name=''):
-    """
-    A static file parser that loads data from an egg using
-    ``pkg_resources``.  Takes a configuration value ``egg``, which is
-    an egg spec, and a base ``resource_name`` (default empty string)
-    which is the path in the egg that this starts at.
-    """
-    if pkg_resources is None:
-        raise NotImplementedError("This function requires pkg_resources.")
-    return PkgResourcesParser(egg, resource_name)
-
-def make_url_parser(global_conf, directory, base_python_name,
-                    index_names=None, hide_extensions=None,
-                    ignore_extensions=None,
-                    **constructor_conf):
-    """
-    Create a URLParser application that looks in ``directory``, which
-    should be the directory for the Python package named in
-    ``base_python_name``.  ``index_names`` are used when viewing the
-    directory (like ``'index'`` for ``'index.html'``).
-    ``hide_extensions`` are extensions that are not viewable (like
-    ``'.pyc'``) and ``ignore_extensions`` are viewable but only if an
-    explicit extension is given.
-    """
-    if index_names is None:
-        index_names = global_conf.get(
-            'index_names', ('index', 'Index', 'main', 'Main'))
-    index_names = converters.aslist(index_names)
-
-    if hide_extensions is None:
-        hide_extensions = global_conf.get(
-            'hide_extensions', ('.pyc', 'bak', 'py~'))
-    hide_extensions = converters.aslist(hide_extensions)
-    
-    if ignore_extensions is None:
-        ignore_extensions = global_conf.get(
-            'ignore_extensions', ())
-    ignore_extensions = converters.aslist(ignore_extensions)
-    # There's no real way to set constructors currently...
-    
-    return URLParser({}, directory, base_python_name,
-                     index_names=index_names,
-                     hide_extensions=hide_extensions,
-                     ignore_extensions=ignore_extensions,
-                     **constructor_conf)
-
diff --git a/lib/paste/util/PySourceColor.py b/lib/paste/util/PySourceColor.py
@@ -1,2103 +0,0 @@
-# -*- coding: Latin-1 -*-
-"""
-PySourceColor: color Python source code
-"""
-
-"""
- PySourceColor.py
-
-----------------------------------------------------------------------------
-
- A python source to colorized html/css/xhtml converter.
- Hacked by M.E.Farmer Jr. 2004, 2005
- Python license
-
-----------------------------------------------------------------------------
-
- - HTML markup does not create w3c valid html, but it works on every
-   browser i've tried so far.(I.E.,Mozilla/Firefox,Opera,Konqueror,wxHTML).
- - CSS markup is w3c validated html 4.01 strict,
-   but will not render correctly on all browsers.
- - XHTML markup is w3c validated xhtml 1.0 strict,
-   like html 4.01, will not render correctly on all browsers.
-
-----------------------------------------------------------------------------
-
-Features:
-
- -Three types of markup:
-    html (default) 
-    css/html 4.01 strict
-    xhtml 1.0 strict
-
- -Can tokenize and colorize:
-    12 types of strings
-    2 comment types
-    numbers
-    operators
-    brackets
-    math operators
-    class / name
-    def / name
-    decorator / name
-    keywords
-    arguments class/def/decorator
-    linenumbers
-    names
-    text
-
- -Eight colorschemes built-in:
-    null
-    mono
-    lite (default)
-    dark 
-    dark2
-    idle
-    viewcvs
-    pythonwin
-
- -Header and footer
-    set to '' for builtin header / footer.
-    give path to a file containing the html
-        you want added as header or footer.
-
- -Arbitrary text and html
-    html markup converts all to raw (TEXT token)
-    #@# for raw -> send raw text.
-    #$# for span -> inline html and text.
-    #%# for div -> block level html and text.
-
- -Linenumbers
-    Supports all styles. New token is called LINENUMBER.
-    Defaults to NAME if not defined.
-
- Style options
- 
- -ALL markups support these text styles:
-         b = bold
-         i = italic
-         u = underline
- -CSS and XHTML has limited support  for borders:
-     HTML markup functions will ignore these.
-     Optional: Border color in RGB hex
-     Defaults to the text forecolor.
-         #rrggbb = border color
-     Border size:
-         l = thick
-         m = medium
-         t = thin
-     Border type:
-         - = dashed
-         . = dotted
-         s = solid
-         d = double
-         g = groove
-         r = ridge
-         n = inset
-         o = outset
-     You can specify multiple sides,
-     they will all use the same style.
-     Optional: Default is full border.
-         v = bottom
-         < = left
-         > = right
-         ^ = top
-     NOTE: Specify the styles you want.
-           The markups will ignore unsupported styles
-           Also note not all browsers can show these options
-
- -All tokens default to NAME if not defined
-     so the only absolutely critical ones to define are:
-     NAME, ERRORTOKEN, PAGEBACKGROUND
-
-----------------------------------------------------------------------------
-
-Example usage::
-
- # import
- import PySourceColor as psc
- psc.convert('c:/Python22/PySourceColor.py', colors=psc.idle, show=1)
-
- # from module import *
- from PySourceColor import *
- convert('c:/Python22/Lib', colors=lite, markup="css",
-          header='#$#<b>This is a simpe heading</b><hr/>')
-
- # How to use a custom colorscheme, and most of the 'features'
- from PySourceColor import *
- new = {
-   ERRORTOKEN:             ('bui','#FF8080',''),
-   DECORATOR_NAME:         ('s','#AACBBC',''),
-   DECORATOR:              ('n','#333333',''),
-   NAME:                   ('t.<v','#1133AA','#DDFF22'),
-   NUMBER:                 ('','#236676','#FF5555'),
-   OPERATOR:               ('b','#454567','#BBBB11'),
-   MATH_OPERATOR:          ('','#935623','#423afb'),
-   BRACKETS:               ('b','#ac34bf','#6457a5'),
-   COMMENT:                ('t-#0022FF','#545366','#AABBFF'),
-   DOUBLECOMMENT:          ('<l#553455','#553455','#FF00FF'),
-   CLASS_NAME:             ('m^v-','#000000','#FFFFFF'),
-   DEF_NAME:               ('l=<v','#897845','#000022'),
-   KEYWORD:                ('.b','#345345','#FFFF22'),
-   SINGLEQUOTE:            ('mn','#223344','#AADDCC'),
-   SINGLEQUOTE_R:          ('','#344522',''),
-   SINGLEQUOTE_U:          ('','#234234',''),
-   DOUBLEQUOTE:            ('m#0022FF','#334421',''),
-   DOUBLEQUOTE_R:          ('','#345345',''),
-   DOUBLEQUOTE_U:          ('','#678673',''),
-   TRIPLESINGLEQUOTE:      ('tv','#FFFFFF','#000000'),
-   TRIPLESINGLEQUOTE_R:    ('tbu','#443256','#DDFFDA'),
-   TRIPLESINGLEQUOTE_U:    ('','#423454','#DDFFDA'),
-   TRIPLEDOUBLEQUOTE:      ('li#236fd3b<>','#000000','#FFFFFF'),
-   TRIPLEDOUBLEQUOTE_R:    ('tub','#000000','#FFFFFF'),
-   TRIPLEDOUBLEQUOTE_U:    ('-', '#CCAABB','#FFFAFF'),
-   LINENUMBER:             ('ib-','#ff66aa','#7733FF'),]
-   TEXT:                   ('','#546634',''), 
-   PAGEBACKGROUND:         '#FFFAAA',
-     }
- if __name__ == '__main__':
-     import sys
-     convert(sys.argv[1], './xhtml.html', colors=new, markup='xhtml', show=1,
-             linenumbers=1)
-     convert(sys.argv[1], './html.html', colors=new, markup='html', show=1,
-             linenumbers=1)
-
-"""
-
-__all__ = ['ERRORTOKEN','DECORATOR_NAME', 'DECORATOR', 'ARGS', 'EXTRASPACE',
-       'NAME', 'NUMBER', 'OPERATOR', 'COMMENT', 'MATH_OPERATOR',
-       'DOUBLECOMMENT', 'CLASS_NAME', 'DEF_NAME', 'KEYWORD', 'BRACKETS',
-       'SINGLEQUOTE','SINGLEQUOTE_R','SINGLEQUOTE_U','DOUBLEQUOTE',
-       'DOUBLEQUOTE_R', 'DOUBLEQUOTE_U', 'TRIPLESINGLEQUOTE', 'TEXT', 
-       'TRIPLESINGLEQUOTE_R', 'TRIPLESINGLEQUOTE_U', 'TRIPLEDOUBLEQUOTE',
-       'TRIPLEDOUBLEQUOTE_R', 'TRIPLEDOUBLEQUOTE_U', 'PAGEBACKGROUND',
-       'LINENUMBER', 'CODESTART', 'CODEEND', 'PY', 'TOKEN_NAMES', 'CSSHOOK',
-       'null', 'mono', 'lite', 'dark','dark2', 'pythonwin','idle', 
-       'viewcvs', 'Usage', 'cli', 'str2stdout', 'path2stdout', 'Parser',
-       'str2file', 'str2html', 'str2css', 'str2markup', 'path2file',
-       'path2html', 'convert', 'walkdir', 'defaultColors', 'showpage',
-       'pageconvert','tagreplace', 'MARKUPDICT']
-__title__ = 'PySourceColor'
-__version__ = "2.1a"
-__date__ = '25 April 2005'
-__author__ = "M.E.Farmer Jr."
-__credits__ = '''This was originally based on a python recipe
-submitted by Jürgen Hermann to ASPN. Now based on the voices in my head.
-M.E.Farmer 2004, 2005
-Python license
-'''
-import os
-import sys
-import time
-import glob
-import getopt
-import keyword
-import token
-import tokenize
-import traceback
-try :
-    import cStringIO as StringIO
-except:
-    import StringIO
-# Do not edit
-NAME = token.NAME
-NUMBER = token.NUMBER
-COMMENT = tokenize.COMMENT
-OPERATOR = token.OP
-ERRORTOKEN = token.ERRORTOKEN
-ARGS = token.NT_OFFSET + 1
-DOUBLECOMMENT = token.NT_OFFSET + 2
-CLASS_NAME = token.NT_OFFSET + 3
-DEF_NAME = token.NT_OFFSET + 4
-KEYWORD = token.NT_OFFSET + 5
-SINGLEQUOTE = token.NT_OFFSET + 6
-SINGLEQUOTE_R = token.NT_OFFSET + 7
-SINGLEQUOTE_U = token.NT_OFFSET + 8
-DOUBLEQUOTE = token.NT_OFFSET + 9
-DOUBLEQUOTE_R = token.NT_OFFSET + 10
-DOUBLEQUOTE_U = token.NT_OFFSET + 11
-TRIPLESINGLEQUOTE = token.NT_OFFSET + 12
-TRIPLESINGLEQUOTE_R = token.NT_OFFSET + 13
-TRIPLESINGLEQUOTE_U = token.NT_OFFSET + 14
-TRIPLEDOUBLEQUOTE = token.NT_OFFSET + 15
-TRIPLEDOUBLEQUOTE_R = token.NT_OFFSET + 16
-TRIPLEDOUBLEQUOTE_U = token.NT_OFFSET + 17
-PAGEBACKGROUND = token.NT_OFFSET + 18
-DECORATOR = token.NT_OFFSET + 19
-DECORATOR_NAME = token.NT_OFFSET + 20
-BRACKETS = token.NT_OFFSET + 21
-MATH_OPERATOR = token.NT_OFFSET + 22
-LINENUMBER = token.NT_OFFSET + 23
-TEXT = token.NT_OFFSET + 24
-PY = token.NT_OFFSET + 25
-CODESTART = token.NT_OFFSET + 26
-CODEEND = token.NT_OFFSET + 27
-CSSHOOK = token.NT_OFFSET + 28
-EXTRASPACE = token.NT_OFFSET + 29
-
-# markup classname lookup
-MARKUPDICT = {
-        ERRORTOKEN:             'py_err',
-        DECORATOR_NAME:         'py_decn',
-        DECORATOR:              'py_dec',
-        ARGS:                   'py_args',
-        NAME:                   'py_name',
-        NUMBER:                 'py_num',
-        OPERATOR:               'py_op',
-        COMMENT:                'py_com',
-        DOUBLECOMMENT:          'py_dcom',
-        CLASS_NAME:             'py_clsn',
-        DEF_NAME:               'py_defn',
-        KEYWORD:                'py_key',
-        SINGLEQUOTE:            'py_sq',
-        SINGLEQUOTE_R:          'py_sqr',
-        SINGLEQUOTE_U:          'py_squ',
-        DOUBLEQUOTE:            'py_dq',
-        DOUBLEQUOTE_R:          'py_dqr',
-        DOUBLEQUOTE_U:          'py_dqu',
-        TRIPLESINGLEQUOTE:      'py_tsq',
-        TRIPLESINGLEQUOTE_R:    'py_tsqr',
-        TRIPLESINGLEQUOTE_U:    'py_tsqu',
-        TRIPLEDOUBLEQUOTE:      'py_tdq',
-        TRIPLEDOUBLEQUOTE_R:    'py_tdqr',
-        TRIPLEDOUBLEQUOTE_U:    'py_tdqu',
-        BRACKETS:               'py_bra',
-        MATH_OPERATOR:          'py_mop',
-        LINENUMBER:             'py_lnum',
-        TEXT:                   'py_text',
-        }
-# might help users that want to create custom schemes
-TOKEN_NAMES= {
-       ERRORTOKEN:'ERRORTOKEN',
-       DECORATOR_NAME:'DECORATOR_NAME',
-       DECORATOR:'DECORATOR',
-       ARGS:'ARGS',
-       NAME:'NAME',
-       NUMBER:'NUMBER',
-       OPERATOR:'OPERATOR',
-       COMMENT:'COMMENT',
-       DOUBLECOMMENT:'DOUBLECOMMENT',
-       CLASS_NAME:'CLASS_NAME',
-       DEF_NAME:'DEF_NAME',
-       KEYWORD:'KEYWORD',
-       SINGLEQUOTE:'SINGLEQUOTE',
-       SINGLEQUOTE_R:'SINGLEQUOTE_R',
-       SINGLEQUOTE_U:'SINGLEQUOTE_U',
-       DOUBLEQUOTE:'DOUBLEQUOTE',
-       DOUBLEQUOTE_R:'DOUBLEQUOTE_R',
-       DOUBLEQUOTE_U:'DOUBLEQUOTE_U',
-       TRIPLESINGLEQUOTE:'TRIPLESINGLEQUOTE',
-       TRIPLESINGLEQUOTE_R:'TRIPLESINGLEQUOTE_R',
-       TRIPLESINGLEQUOTE_U:'TRIPLESINGLEQUOTE_U',
-       TRIPLEDOUBLEQUOTE:'TRIPLEDOUBLEQUOTE',
-       TRIPLEDOUBLEQUOTE_R:'TRIPLEDOUBLEQUOTE_R',
-       TRIPLEDOUBLEQUOTE_U:'TRIPLEDOUBLEQUOTE_U',
-       BRACKETS:'BRACKETS',
-       MATH_OPERATOR:'MATH_OPERATOR',
-       LINENUMBER:'LINENUMBER',
-       TEXT:'TEXT',
-       PAGEBACKGROUND:'PAGEBACKGROUND',
-       }
-
-######################################################################
-# Edit colors and styles to taste
-# Create your own scheme, just copy one below , rename and edit.
-# Custom styles must at least define NAME, ERRORTOKEN, PAGEBACKGROUND,
-# all missing elements will default to NAME.
-# See module docstring for details on style attributes.
-######################################################################
-# Copy null and use it as a starter colorscheme.
-null = {# tokentype: ('tags border_color', 'textforecolor', 'textbackcolor')
-        ERRORTOKEN:             ('','#000000',''),# Error token
-        DECORATOR_NAME:         ('','#000000',''),# Decorator name
-        DECORATOR:              ('','#000000',''),# @ symbol
-        ARGS:                   ('','#000000',''),# class,def,deco arguments
-        NAME:                   ('','#000000',''),# All other python text
-        NUMBER:                 ('','#000000',''),# 0->10
-        OPERATOR:               ('','#000000',''),# ':','<=',';',',','.','==', etc
-        MATH_OPERATOR:          ('','#000000',''),# '+','-','=','','**',etc
-        BRACKETS:               ('','#000000',''),# '[',']','(',')','{','}'
-        COMMENT:                ('','#000000',''),# Single comment
-        DOUBLECOMMENT:          ('','#000000',''),## Double comment
-        CLASS_NAME:             ('','#000000',''),# Class name
-        DEF_NAME:               ('','#000000',''),# Def name
-        KEYWORD:                ('','#000000',''),# Python keywords
-        SINGLEQUOTE:            ('','#000000',''),# 'SINGLEQUOTE'
-        SINGLEQUOTE_R:          ('','#000000',''),# r'SINGLEQUOTE'
-        SINGLEQUOTE_U:          ('','#000000',''),# u'SINGLEQUOTE'
-        DOUBLEQUOTE:            ('','#000000',''),# "DOUBLEQUOTE"
-        DOUBLEQUOTE_R:          ('','#000000',''),# r"DOUBLEQUOTE"
-        DOUBLEQUOTE_U:          ('','#000000',''),# u"DOUBLEQUOTE"
-        TRIPLESINGLEQUOTE:      ('','#000000',''),# '''TRIPLESINGLEQUOTE'''
-        TRIPLESINGLEQUOTE_R:    ('','#000000',''),# r'''TRIPLESINGLEQUOTE'''
-        TRIPLESINGLEQUOTE_U:    ('','#000000',''),# u'''TRIPLESINGLEQUOTE'''
-        TRIPLEDOUBLEQUOTE:      ('','#000000',''),# """TRIPLEDOUBLEQUOTE"""
-        TRIPLEDOUBLEQUOTE_R:    ('','#000000',''),# r"""TRIPLEDOUBLEQUOTE"""
-        TRIPLEDOUBLEQUOTE_U:    ('','#000000',''),# u"""TRIPLEDOUBLEQUOTE"""
-        TEXT:                   ('','#000000',''),# non python text 
-        LINENUMBER:             ('>ti#555555','#000000',''),# Linenumbers
-        PAGEBACKGROUND:         '#FFFFFF'# set the page background
-        }
-
-mono = {
-        ERRORTOKEN:             ('s#FF0000','#FF8080',''),
-        DECORATOR_NAME:         ('bu','#000000',''),
-        DECORATOR:              ('b','#000000',''),
-        ARGS:                   ('b','#555555',''),
-        NAME:                   ('','#000000',''),
-        NUMBER:                 ('b','#000000',''),
-        OPERATOR:               ('b','#000000',''),
-        MATH_OPERATOR:          ('b','#000000',''),
-        BRACKETS:               ('b','#000000',''),
-        COMMENT:                ('i','#999999',''),
-        DOUBLECOMMENT:          ('b','#999999',''),
-        CLASS_NAME:             ('bu','#000000',''),
-        DEF_NAME:               ('b','#000000',''),
-        KEYWORD:                ('b','#000000',''),
-        SINGLEQUOTE:            ('','#000000',''),
-        SINGLEQUOTE_R:          ('','#000000',''),
-        SINGLEQUOTE_U:          ('','#000000',''),
-        DOUBLEQUOTE:            ('','#000000',''),
-        DOUBLEQUOTE_R:          ('','#000000',''),
-        DOUBLEQUOTE_U:          ('','#000000',''),
-        TRIPLESINGLEQUOTE:      ('','#000000',''),
-        TRIPLESINGLEQUOTE_R:    ('','#000000',''),
-        TRIPLESINGLEQUOTE_U:    ('','#000000',''),
-        TRIPLEDOUBLEQUOTE:      ('i','#000000',''),
-        TRIPLEDOUBLEQUOTE_R:    ('i','#000000',''),
-        TRIPLEDOUBLEQUOTE_U:    ('i','#000000',''),
-        TEXT:                   ('','#000000',''),
-        LINENUMBER:             ('>ti#555555','#000000',''),
-        PAGEBACKGROUND:         '#FFFFFF'
-        }
-
-dark = {
-        ERRORTOKEN:             ('s#FF0000','#FF8080',''),
-        DECORATOR_NAME:         ('b','#FFBBAA',''),
-        DECORATOR:              ('b','#CC5511',''),
-        ARGS:                   ('b','#DDDDFF',''),
-        NAME:                   ('','#DDDDDD',''),
-        NUMBER:                 ('','#FF0000',''),
-        OPERATOR:               ('b','#FAF785',''),
-        MATH_OPERATOR:          ('b','#FAF785',''),
-        BRACKETS:               ('b','#FAF785',''),
-        COMMENT:                ('','#45FCA0',''),
-        DOUBLECOMMENT:          ('i','#A7C7A9',''),
-        CLASS_NAME:             ('b','#B666FD',''),
-        DEF_NAME:               ('b','#EBAE5C',''),
-        KEYWORD:                ('b','#8680FF',''),
-        SINGLEQUOTE:            ('','#F8BAFE',''),
-        SINGLEQUOTE_R:          ('','#F8BAFE',''),
-        SINGLEQUOTE_U:          ('','#F8BAFE',''),
-        DOUBLEQUOTE:            ('','#FF80C0',''),
-        DOUBLEQUOTE_R:          ('','#FF80C0',''),
-        DOUBLEQUOTE_U:          ('','#FF80C0',''),
-        TRIPLESINGLEQUOTE:      ('','#FF9595',''),
-        TRIPLESINGLEQUOTE_R:    ('','#FF9595',''),
-        TRIPLESINGLEQUOTE_U:    ('','#FF9595',''),
-        TRIPLEDOUBLEQUOTE:      ('','#B3FFFF',''),
-        TRIPLEDOUBLEQUOTE_R:    ('','#B3FFFF',''),
-        TRIPLEDOUBLEQUOTE_U:    ('','#B3FFFF',''),
-        TEXT:                   ('','#FFFFFF',''),
-        LINENUMBER:             ('>mi#555555','#bbccbb','#333333'),
-        PAGEBACKGROUND:         '#000000'
-        }
-
-dark2 = {
-        ERRORTOKEN:             ('','#FF0000',''),
-        DECORATOR_NAME:         ('b','#FFBBAA',''),
-        DECORATOR:              ('b','#CC5511',''),
-        ARGS:                   ('b','#DDDDDD',''),
-        NAME:                   ('','#C0C0C0',''),
-        NUMBER:                 ('b','#00FF00',''),
-        OPERATOR:               ('b','#FF090F',''),
-        MATH_OPERATOR:          ('b','#EE7020',''),
-        BRACKETS:               ('b','#FFB90F',''),
-        COMMENT:                ('i','#D0D000','#522000'),#'#88AA88','#11111F'),
-        DOUBLECOMMENT:          ('i','#D0D000','#522000'),#'#77BB77','#11111F'),
-        CLASS_NAME:             ('b','#DD4080',''),
-        DEF_NAME:               ('b','#FF8040',''),
-        KEYWORD:                ('b','#4726d1',''),
-        SINGLEQUOTE:            ('','#8080C0',''),
-        SINGLEQUOTE_R:          ('','#8080C0',''),
-        SINGLEQUOTE_U:          ('','#8080C0',''),
-        DOUBLEQUOTE:            ('','#ADB9F1',''),
-        DOUBLEQUOTE_R:          ('','#ADB9F1',''),
-        DOUBLEQUOTE_U:          ('','#ADB9F1',''),
-        TRIPLESINGLEQUOTE:      ('','#00C1C1',''),#A050C0
-        TRIPLESINGLEQUOTE_R:    ('','#00C1C1',''),#A050C0
-        TRIPLESINGLEQUOTE_U:    ('','#00C1C1',''),#A050C0
-        TRIPLEDOUBLEQUOTE:      ('','#33E3E3',''),#B090E0
-        TRIPLEDOUBLEQUOTE_R:    ('','#33E3E3',''),#B090E0
-        TRIPLEDOUBLEQUOTE_U:    ('','#33E3E3',''),#B090E0
-        TEXT:                   ('','#C0C0C0',''),
-        LINENUMBER:             ('>mi#555555','#bbccbb','#333333'),
-        PAGEBACKGROUND:         '#000000'
-        }
-
-lite = {
-        ERRORTOKEN:             ('s#FF0000','#FF8080',''),
-        DECORATOR_NAME:         ('b','#BB4422',''),
-        DECORATOR:              ('b','#3333AF',''),
-        ARGS:                   ('b','#000000',''),
-        NAME:                   ('','#333333',''),
-        NUMBER:                 ('b','#DD2200',''),
-        OPERATOR:               ('b','#000000',''),
-        MATH_OPERATOR:          ('b','#000000',''),
-        BRACKETS:               ('b','#000000',''),
-        COMMENT:                ('','#007F00',''),
-        DOUBLECOMMENT:          ('','#608060',''),
-        CLASS_NAME:             ('b','#0000DF',''),
-        DEF_NAME:               ('b','#9C7A00',''),#f09030
-        KEYWORD:                ('b','#0000AF',''),
-        SINGLEQUOTE:            ('','#600080',''),
-        SINGLEQUOTE_R:          ('','#600080',''),
-        SINGLEQUOTE_U:          ('','#600080',''),
-        DOUBLEQUOTE:            ('','#A0008A',''),
-        DOUBLEQUOTE_R:          ('','#A0008A',''),
-        DOUBLEQUOTE_U:          ('','#A0008A',''),
-        TRIPLESINGLEQUOTE:      ('','#337799',''),
-        TRIPLESINGLEQUOTE_R:    ('','#337799',''),
-        TRIPLESINGLEQUOTE_U:    ('','#337799',''),
-        TRIPLEDOUBLEQUOTE:      ('','#1166AA',''),
-        TRIPLEDOUBLEQUOTE_R:    ('','#1166AA',''),
-        TRIPLEDOUBLEQUOTE_U:    ('','#1166AA',''),
-        TEXT:                   ('','#000000',''),
-        LINENUMBER:             ('>ti#555555','#000000',''),
-        PAGEBACKGROUND:         '#FFFFFF'
-        }
-
-idle = {
-        ERRORTOKEN:             ('s#FF0000','#FF8080',''),
-        DECORATOR_NAME:         ('','#900090',''),
-        DECORATOR:              ('','#FF7700',''),
-        NAME:                   ('','#000000',''),
-        NUMBER:                 ('','#000000',''),
-        OPERATOR:               ('','#000000',''),
-        MATH_OPERATOR:          ('','#000000',''),
-        BRACKETS:               ('','#000000',''),
-        COMMENT:                ('','#DD0000',''),
-        DOUBLECOMMENT:          ('','#DD0000',''),
-        CLASS_NAME:             ('','#0000FF',''),
-        DEF_NAME:               ('','#0000FF',''),
-        KEYWORD:                ('','#FF7700',''),
-        SINGLEQUOTE:            ('','#00AA00',''),
-        SINGLEQUOTE_R:          ('','#00AA00',''),
-        SINGLEQUOTE_U:          ('','#00AA00',''),
-        DOUBLEQUOTE:            ('','#00AA00',''),
-        DOUBLEQUOTE_R:          ('','#00AA00',''),
-        DOUBLEQUOTE_U:          ('','#00AA00',''),
-        TRIPLESINGLEQUOTE:      ('','#00AA00',''),
-        TRIPLESINGLEQUOTE_R:    ('','#00AA00',''),
-        TRIPLESINGLEQUOTE_U:    ('','#00AA00',''),
-        TRIPLEDOUBLEQUOTE:      ('','#00AA00',''),
-        TRIPLEDOUBLEQUOTE_R:    ('','#00AA00',''),
-        TRIPLEDOUBLEQUOTE_U:    ('','#00AA00',''),
-        TEXT:                   ('','#000000',''),
-        LINENUMBER:             ('>ti#555555','#000000',''),
-        PAGEBACKGROUND:         '#FFFFFF'
-        }
-
-pythonwin = {
-        ERRORTOKEN:             ('s#FF0000','#FF8080',''),
-        DECORATOR_NAME:         ('b','#DD0080',''),
-        DECORATOR:              ('b','#000080',''),
-        ARGS:                   ('','#000000',''),
-        NAME:                   ('','#303030',''),
-        NUMBER:                 ('','#008080',''),
-        OPERATOR:               ('','#000000',''),
-        MATH_OPERATOR:          ('','#000000',''),
-        BRACKETS:               ('','#000000',''),
-        COMMENT:                ('','#007F00',''),
-        DOUBLECOMMENT:          ('','#7F7F7F',''),
-        CLASS_NAME:             ('b','#0000FF',''),
-        DEF_NAME:               ('b','#007F7F',''),
-        KEYWORD:                ('b','#000080',''),
-        SINGLEQUOTE:            ('','#808000',''),
-        SINGLEQUOTE_R:          ('','#808000',''),
-        SINGLEQUOTE_U:          ('','#808000',''),
-        DOUBLEQUOTE:            ('','#808000',''),
-        DOUBLEQUOTE_R:          ('','#808000',''),
-        DOUBLEQUOTE_U:          ('','#808000',''),
-        TRIPLESINGLEQUOTE:      ('','#808000',''),
-        TRIPLESINGLEQUOTE_R:    ('','#808000',''),
-        TRIPLESINGLEQUOTE_U:    ('','#808000',''),
-        TRIPLEDOUBLEQUOTE:      ('','#808000',''),
-        TRIPLEDOUBLEQUOTE_R:    ('','#808000',''),
-        TRIPLEDOUBLEQUOTE_U:    ('','#808000',''),
-        TEXT:                   ('','#303030',''),
-        LINENUMBER:             ('>ti#555555','#000000',''),
-        PAGEBACKGROUND:         '#FFFFFF'
-        }
-
-viewcvs = {
-        ERRORTOKEN:             ('s#FF0000','#FF8080',''),
-        DECORATOR_NAME:         ('','#000000',''),
-        DECORATOR:              ('','#000000',''),
-        ARGS:                   ('','#000000',''),
-        NAME:                   ('','#000000',''),
-        NUMBER:                 ('','#000000',''),
-        OPERATOR:               ('','#000000',''),
-        MATH_OPERATOR:          ('','#000000',''),
-        BRACKETS:               ('','#000000',''),
-        COMMENT:                ('i','#b22222',''),
-        DOUBLECOMMENT:          ('i','#b22222',''),
-        CLASS_NAME:             ('','#000000',''),
-        DEF_NAME:               ('b','#0000ff',''),
-        KEYWORD:                ('b','#a020f0',''),
-        SINGLEQUOTE:            ('b','#bc8f8f',''),
-        SINGLEQUOTE_R:          ('b','#bc8f8f',''),
-        SINGLEQUOTE_U:          ('b','#bc8f8f',''),
-        DOUBLEQUOTE:            ('b','#bc8f8f',''),
-        DOUBLEQUOTE_R:          ('b','#bc8f8f',''),
-        DOUBLEQUOTE_U:          ('b','#bc8f8f',''),
-        TRIPLESINGLEQUOTE:      ('b','#bc8f8f',''),
-        TRIPLESINGLEQUOTE_R:    ('b','#bc8f8f',''),
-        TRIPLESINGLEQUOTE_U:    ('b','#bc8f8f',''),
-        TRIPLEDOUBLEQUOTE:      ('b','#bc8f8f',''),
-        TRIPLEDOUBLEQUOTE_R:    ('b','#bc8f8f',''),
-        TRIPLEDOUBLEQUOTE_U:    ('b','#bc8f8f',''),
-        TEXT:                   ('','#000000',''),
-        LINENUMBER:             ('>ti#555555','#000000',''),
-        PAGEBACKGROUND:         '#FFFFFF'
-        }
-
-defaultColors = lite
-
-def Usage():
-    doc = """
- -----------------------------------------------------------------------------
-  PySourceColor.py ver: %s
- -----------------------------------------------------------------------------
-  Module summary:
-     This module is designed to colorize python source code.
-         Input--->python source
-         Output-->colorized (html, html4.01/css, xhtml1.0)
-     Standalone:
-         This module will work from the command line with options.
-         This module will work with redirected stdio.
-     Imported:
-         This module can be imported and used directly in your code.
- -----------------------------------------------------------------------------
-  Command line options:
-     -h, --help
-         Optional-> Display this help message.
-     -t, --test
-         Optional-> Will ignore all others flags but  --profile
-             test all schemes and markup combinations
-     -p, --profile
-         Optional-> Works only with --test or -t
-             runs profile.py and makes the test work in quiet mode.
-     -i, --in, --input
-         Optional-> If you give input on stdin.
-         Use any of these for the current dir (.,cwd)
-         Input can be file or dir.
-         Input from stdin use one of the following (-,stdin)
-         If stdin is used as input stdout is output unless specified.
-     -o, --out, --output
-         Optional-> output dir for the colorized source.
-             default: output dir is the input dir.
-         To output html to stdout use one of the following (-,stdout)
-         Stdout can be used without stdin if you give a file as input.
-     -c, --color
-         Optional-> null, mono, dark, dark2, lite, idle, pythonwin, viewcvs
-             default: dark 
-     -s, --show
-         Optional-> Show page after creation.
-             default: no show
-     -m, --markup
-         Optional-> html, css, xhtml
-             css, xhtml also support external stylesheets (-e,--external)
-             default: HTML
-     -e, --external
-         Optional-> use with css, xhtml
-             Writes an style sheet instead of embedding it in the page
-             saves it as pystyle.css in the same directory.
-             html markup will silently ignore this flag.
-     -H, --header
-         Opional-> add a page header to the top of the output
-         -H
-             Builtin header (name,date,hrule)
-         --header
-             You must specify a filename.
-             The header file must be valid html
-             and must handle its own font colors.
-             ex. --header c:/tmp/header.txt
-     -F, --footer
-         Opional-> add a page footer to the bottom of the output
-         -F 
-             Builtin footer (hrule,name,date)
-         --footer
-             You must specify a filename.
-             The footer file must be valid html
-             and must handle its own font colors.
-             ex. --footer c:/tmp/footer.txt  
-     -l, --linenumbers
-         Optional-> default is no linenumbers
-             Adds line numbers to the start of each line in the code.
-    --convertpage
-         Given a webpage that has code embedded in tags it will
-             convert embedded code to colorized html. 
-             (see pageconvert for details)
- -----------------------------------------------------------------------------
-  Option usage:
-   # Test and show pages
-      python PySourceColor.py -t -s
-   # Test and only show profile results
-      python PySourceColor.py -t -p
-   # Colorize all .py,.pyw files in cwdir you can also use: (.,cwd)
-      python PySourceColor.py -i .
-   # Using long options w/ =
-      python PySourceColor.py --in=c:/myDir/my.py --color=lite --show
-   # Using short options w/out =
-      python PySourceColor.py -i c:/myDir/  -c idle -m css -e
-   # Using any mix
-      python PySourceColor.py --in . -o=c:/myDir --show
-   # Place a custom header on your files
-      python PySourceColor.py -i . -o c:/tmp -m xhtml --header c:/header.txt
- -----------------------------------------------------------------------------
-  Stdio usage:
-   # Stdio using no options
-      python PySourceColor.py < c:/MyFile.py > c:/tmp/MyFile.html
-   # Using stdin alone automatically uses stdout for output: (stdin,-)
-      python PySourceColor.py -i- < c:/MyFile.py > c:/tmp/myfile.html
-   # Stdout can also be written to directly from a file instead of stdin
-      python PySourceColor.py -i c:/MyFile.py -m css -o- > c:/tmp/myfile.html
-   # Stdin can be used as input , but output can still be specified
-      python PySourceColor.py -i- -o c:/pydoc.py.html -s < c:/Python22/my.py
- _____________________________________________________________________________
- """
-    print doc % (__version__)
-    sys.exit(1)
-
-###################################################### Command line interface
-
-def cli():
-    """Handle command line args and redirections"""
-    try:
-        # try to get command line args
-        opts, args = getopt.getopt(sys.argv[1:],
-              "hseqtplHFi:o:c:m:h:f:",["help", "show", "quiet", 
-              "test", "external", "linenumbers", "convertpage", "profile", 
-              "input=", "output=", "color=", "markup=","header=", "footer="])
-    except getopt.GetoptError:
-        # on error print help information and exit:
-        Usage()
-    # init some names
-    input = None
-    output = None
-    colorscheme = None
-    markup = 'html'
-    header = None
-    footer = None
-    linenumbers = 0
-    show = 0
-    quiet = 0
-    test = 0
-    profile = 0
-    convertpage = 0
-    form = None
-    # if we have args then process them
-    for o, a in opts:
-        if o in ["-h", "--help"]:
-            Usage()
-            sys.exit()
-        if o in ["-o", "--output", "--out"]:
-            output = a
-        if o in ["-i", "--input", "--in"]:
-            input = a
-            if input in [".", "cwd"]:
-                input = os.getcwd()
-        if o in ["-s", "--show"]:
-            show = 1
-        if o in ["-q", "--quiet"]:
-            quiet = 1
-        if o in ["-t", "--test"]:
-            test = 1
-        if o in ["--convertpage"]:
-            convertpage = 1
-        if o in ["-p", "--profile"]:
-            profile = 1
-        if o in ["-e", "--external"]:
-            form = 'external'
-        if o in ["-m", "--markup"]:
-            markup = str(a)
-        if o in ["-l", "--linenumbers"]:
-            linenumbers = 1
-        if o in ["--header"]:
-            header = str(a)
-        elif o == "-H":
-            header = ''
-        if o in ["--footer"]:
-            footer = str(a)
-        elif o == "-F":
-            footer = ''
-        if o in ["-c", "--color"]:
-            try:
-                colorscheme = globals().get(a.lower())
-            except:
-                traceback.print_exc()
-                Usage()
-    if test:
-        if profile:
-            import profile
-            profile.run('_test(show=%s, quiet=%s)'%(show,quiet))
-        else:
-            # Parse this script in every possible colorscheme and markup
-            _test(show,quiet)
-    elif input in [None, "-", "stdin"] or output in ["-", "stdout"]:
-        # determine if we are going to use stdio
-        if input not in [None, "-", "stdin"]:
-            if os.path.isfile(input) :
-                path2stdout(input, colors=colorscheme, markup=markup,
-                            linenumbers=linenumbers, header=header, 
-                            footer=footer, form=form)
-            else:
-                raise PathError, 'File does not exists!'
-        else:
-            try:
-                if sys.stdin.isatty():
-                    raise InputError, 'Please check input!'
-                else:
-                    if output in [None,"-","stdout"]:
-                        str2stdout(sys.stdin.read(), colors=colorscheme,
-                                   markup=markup, header=header,
-                                   footer=footer, linenumbers=linenumbers,
-                                   form=form)
-                    else:
-                        str2file(sys.stdin.read(), outfile=output, show=show, 
-                                markup=markup, header=header, footer=footer,
-                                linenumbers=linenumbers, form=form)
-            except:
-                traceback.print_exc()
-                Usage()
-    else:
-        if os.path.exists(input):
-            if convertpage:
-                # if there was at least an input given we can proceed
-                pageconvert(input, out=output, colors=colorscheme, 
-                            show=show, markup=markup,linenumbers=linenumbers)
-            else:
-                # if there was at least an input given we can proceed
-                convert(source=input, outdir=output, colors=colorscheme, 
-                        show=show, markup=markup, quiet=quiet, header=header,
-                        footer=footer, linenumbers=linenumbers, form=form)
-        else:
-            raise PathError, 'File does not exists!'
-            Usage()
-
-######################################################### Simple markup tests
-
-def _test(show=0, quiet=0):
-    """Test the parser and most of the functions.
-
-       There are 19 test total(eight colorschemes in three diffrent markups,
-       and a str2file test. Most functions are tested by this.
-    """
-    fi = sys.argv[0]
-    if not fi.endswith('.exe'):# Do not test if frozen as an archive
-        # this is a collection of test, most things are covered.
-        path2file(fi, '/tmp/null.html', null, show=show, quiet=quiet)
-        path2file(fi, '/tmp/null_css.html', null, show=show,
-                  markup='css', quiet=quiet)
-        path2file(fi, '/tmp/mono.html', mono, show=show, quiet=quiet)
-        path2file(fi, '/tmp/mono_css.html', mono, show=show,
-                  markup='css', quiet=quiet)
-        path2file(fi, '/tmp/lite.html', lite, show=show, quiet=quiet)
-        path2file(fi, '/tmp/lite_css.html', lite, show=show,
-                  markup='css', quiet=quiet, header='', footer='', 
-                  linenumbers=1)
-        path2file(fi, '/tmp/lite_xhtml.html', lite, show=show,
-                  markup='xhtml', quiet=quiet)
-        path2file(fi, '/tmp/dark.html', dark, show=show, quiet=quiet)
-        path2file(fi, '/tmp/dark_css.html', dark, show=show,
-                  markup='css', quiet=quiet, linenumbers=1)
-        path2file(fi, '/tmp/dark2.html', dark2, show=show, quiet=quiet)
-        path2file(fi, '/tmp/dark2_css.html', dark2, show=show,
-                  markup='css', quiet=quiet)
-        path2file(fi, '/tmp/dark2_xhtml.html', dark2, show=show,
-                  markup='xhtml', quiet=quiet, header='', footer='', 
-                  linenumbers=1, form='external')
-        path2file(fi, '/tmp/idle.html', idle, show=show, quiet=quiet)
-        path2file(fi, '/tmp/idle_css.html', idle, show=show,
-                  markup='css', quiet=quiet)
-        path2file(fi, '/tmp/viewcvs.html', viewcvs, show=show, 
-                  quiet=quiet, linenumbers=1)
-        path2file(fi, '/tmp/viewcvs_css.html', viewcvs, show=show,
-                  markup='css', linenumbers=1, quiet=quiet)
-        path2file(fi, '/tmp/pythonwin.html', pythonwin, show=show,
-                  quiet=quiet)
-        path2file(fi, '/tmp/pythonwin_css.html', pythonwin, show=show,
-                  markup='css', quiet=quiet)
-        teststr=r'''"""This is a test of decorators and other things"""
-# This should be line 421...
-@whatever(arg,arg2)
-@A @B(arghh) @C
-def LlamaSaysNi(arg='Ni!',arg2="RALPH"):
-   """This docstring is deeply disturbed by all the llama references"""
-   print '%s The Wonder Llama says %s'% (arg2,arg)
-# So I was like duh!, and he was like ya know?!,
-# and so we were both like huh...wtf!? RTFM!! LOL!!;)
-@staticmethod## Double comments are KewL.
-def LlamasRLumpy():
-   """This docstring is too sexy to be here.
-   """
-   u"""
-=============================
-A Møøse once bit my sister...
-=============================
-   """
-   ## Relax, this won't hurt a bit, just a simple, painless procedure,
-   ## hold still while I get the anesthetizing hammer.
-   m = {'three':'1','won':'2','too':'3'}
-   o = r'fishy\fishy\fishy/fish\oh/where/is\my/little\..'
-   python = uR""" 
- No realli! She was Karving her initials øn the møøse with the sharpened end  
- of an interspace tøøthbrush given her by Svenge - her brother-in-law -an Oslo
- dentist and star of many Norwegian møvies: "The Høt Hands of an Oslo         
- Dentist", "Fillings of Passion", "The Huge Mølars of Horst Nordfink"..."""
-   RU"""142 MEXICAN WHOOPING LLAMAS"""#<-Can you fit 142 llamas in a red box?
-   n = u' HERMSGERVØRDENBRØTBØRDA ' + """ YUTTE """
-   t = """SAMALLNIATNUOMNAIRODAUCE"""+"DENIARTYLLAICEPS04"
-   ## We apologise for the fault in the
-   ## comments. Those responsible have been
-   ## sacked.
-   y = '14 NORTH CHILEAN GUANACOS \
-(CLOSELY RELATED TO THE LLAMA)'
-   rules = [0,1,2,3,4,5]
-   print y'''
-        htmlPath = os.path.abspath('/tmp/strtest_lines.html')
-        str2file(teststr, htmlPath, colors=dark, markup='xhtml',
-                 linenumbers=420, show=show)
-        _printinfo("  wrote %s" % htmlPath, quiet)
-        htmlPath = os.path.abspath('/tmp/strtest_nolines.html')
-        str2file(teststr, htmlPath, colors=dark, markup='xhtml',
-                 show=show)
-        _printinfo("  wrote %s" % htmlPath, quiet)
-    else:
-        Usage()
-    return
-
-# emacs wants this: '
-
-####################################################### User funtctions
-
-def str2stdout(sourcestring, colors=None, title='', markup='html',
-                 header=None, footer=None,
-                 linenumbers=0, form=None):
-    """Converts a code(string) to colorized HTML. Writes to stdout.
-
-       form='code',or'snip' (for "<pre>yourcode</pre>" only)
-       colors=null,mono,lite,dark,dark2,idle,or pythonwin
-    """
-    Parser(sourcestring, colors=colors, title=title, markup=markup,
-           header=header, footer=footer,
-           linenumbers=linenumbers).format(form)
-
-def path2stdout(sourcepath, title='', colors=None, markup='html',
-                   header=None, footer=None,
-                   linenumbers=0, form=None):
-    """Converts code(file) to colorized HTML. Writes to stdout.
-
-       form='code',or'snip' (for "<pre>yourcode</pre>" only)
-       colors=null,mono,lite,dark,dark2,idle,or pythonwin
-    """
-    sourcestring = open(sourcepath).read()
-    Parser(sourcestring, colors=colors, title=sourcepath, 
-           markup=markup, header=header, footer=footer,
-           linenumbers=linenumbers).format(form)
-
-def str2html(sourcestring, colors=None, title='', 
-               markup='html', header=None, footer=None,
-               linenumbers=0, form=None):
-    """Converts a code(string) to colorized HTML. Returns an HTML string.
-
-       form='code',or'snip' (for "<pre>yourcode</pre>" only)
-       colors=null,mono,lite,dark,dark2,idle,or pythonwin
-    """
-    stringIO = StringIO.StringIO()
-    Parser(sourcestring, colors=colors, title=title, out=stringIO,
-           markup=markup, header=header, footer=footer,
-           linenumbers=linenumbers).format(form)
-    stringIO.seek(0)
-    return stringIO.read()
-  
-def str2css(sourcestring, colors=None, title='',
-              markup='css', header=None, footer=None,  
-              linenumbers=0, form=None):
-    """Converts a code string to colorized CSS/HTML. Returns CSS/HTML string
-       
-       If form != None then this will return (stylesheet_str, code_str)
-       colors=null,mono,lite,dark,dark2,idle,or pythonwin
-    """
-    if markup.lower() not in ['css' ,'xhtml']:
-        markup = 'css'
-    stringIO = StringIO.StringIO()
-    parse = Parser(sourcestring, colors=colors, title=title,
-                   out=stringIO, markup=markup,
-                   header=header, footer=footer,
-                   linenumbers=linenumbers)
-    parse.format(form)
-    stringIO.seek(0)
-    if form != None:
-        return parse._sendCSSStyle(external=1), stringIO.read()
-    else:
-        return None, stringIO.read()
-
-def str2markup(sourcestring, colors=None, title = '',
-               markup='xhtml', header=None, footer=None, 
-              linenumbers=0, form=None):
-    """ Convert code strings into ([stylesheet or None], colorized string) """
-    if markup.lower() == 'html':
-        return None, str2html(sourcestring, colors=colors, title=title,
-                   header=header, footer=footer, markup=markup, 
-                   linenumbers=linenumbers, form=form)
-    else:
-        return str2css(sourcestring, colors=colors, title=title,
-                   header=header, footer=footer, markup=markup, 
-                   linenumbers=linenumbers, form=form)
-
-def str2file(sourcestring, outfile, colors=None, title='', 
-               markup='html', header=None, footer=None, 
-               linenumbers=0, show=0, dosheet=1, form=None):
-    """Converts a code string to a file.
-
-       makes no attempt at correcting bad pathnames
-    """
-    css , html = str2markup(sourcestring, colors=colors, title='',
-                    markup=markup, header=header, footer=footer,
-                    linenumbers=linenumbers, form=form)
-    # write html
-    f = open(outfile,'wt')
-    f.writelines(html)
-    f.close()
-    #write css
-    if css != None and dosheet: 
-        dir = os.path.dirname(outfile)
-        outcss = os.path.join(dir,'pystyle.css')
-        f = open(outcss,'wt')
-        f.writelines(css)
-        f.close()
-    if show:
-        showpage(outfile)
-
-def path2html(sourcepath, colors=None, markup='html',
-                header=None, footer=None,
-                linenumbers=0, form=None):
-    """Converts code(file) to colorized HTML. Returns an HTML string.
-
-       form='code',or'snip' (for "<pre>yourcode</pre>" only)
-       colors=null,mono,lite,dark,dark2,idle,or pythonwin
-    """
-    stringIO = StringIO.StringIO()
-    sourcestring = open(sourcepath).read()
-    Parser(sourcestring, colors, title=sourcepath, out=stringIO,
-           markup=markup, header=header, footer=footer,
-           linenumbers=linenumbers).format(form)
-    stringIO.seek(0)
-    return stringIO.read()
-
-def convert(source, outdir=None, colors=None,
-              show=0, markup='html', quiet=0,
-              header=None, footer=None, linenumbers=0, form=None):
-    """Takes a file or dir as input and places the html in the outdir.
-
-       If outdir is none it defaults to the input dir
-    """
-    count=0
-    # If it is a filename then path2file
-    if not os.path.isdir(source):
-        if os.path.isfile(source):
-            count+=1
-            path2file(source, outdir, colors, show, markup, 
-                     quiet, form, header, footer, linenumbers, count)
-        else:
-            raise PathError, 'File does not exist!'
-    # If we pass in a dir we need to walkdir for files.
-    # Then we need to colorize them with path2file
-    else:
-        fileList = walkdir(source)
-        if fileList != None:
-            # make sure outdir is a dir
-            if outdir != None:
-                if os.path.splitext(outdir)[1] != '':
-                    outdir = os.path.split(outdir)[0]
-            for item in fileList:
-                count+=1
-                path2file(item, outdir, colors, show, markup,
-                          quiet, form, header, footer, linenumbers, count)
-            _printinfo('Completed colorizing %s files.'%str(count), quiet)
-        else:
-            _printinfo("No files to convert in dir.", quiet)
-
-def path2file(sourcePath, out=None, colors=None, show=0,
-                markup='html', quiet=0, form=None,
-                header=None, footer=None, linenumbers=0, count=1):
-    """ Converts python source to html file"""
-    # If no outdir is given we use the sourcePath
-    if out == None:#this is a guess
-        htmlPath = sourcePath + '.html'
-    else:
-        # If we do give an out_dir, and it does
-        # not exist , it will be created.
-        if os.path.splitext(out)[1] == '':
-            if not os.path.isdir(out):
-                os.makedirs(out)
-            sourceName = os.path.basename(sourcePath)
-            htmlPath = os.path.join(out,sourceName)+'.html'
-        # If we do give an out_name, and its dir does
-        # not exist , it will be created.
-        else:
-            outdir = os.path.split(out)[0]
-            if not os.path.isdir(outdir):
-                os.makedirs(outdir)
-            htmlPath = out
-    htmlPath = os.path.abspath(htmlPath)
-    # Open the text and do the parsing.
-    source = open(sourcePath).read()
-    parse = Parser(source, colors, sourcePath, open(htmlPath, 'wt'),
-                   markup, header, footer, linenumbers)
-    parse.format(form)
-    _printinfo("  wrote %s" % htmlPath, quiet)
-    # html markup will ignore the external flag, but
-    # we need to stop the blank file from being written.
-    if form == 'external' and count == 1 and markup != 'html':
-        cssSheet = parse._sendCSSStyle(external=1)
-        cssPath = os.path.join(os.path.dirname(htmlPath),'pystyle.css')
-        css = open(cssPath, 'wt')
-        css.write(cssSheet)
-        css.close()
-        _printinfo("    wrote %s" % cssPath, quiet)
-    if show:
-        # load HTML page into the default web browser.
-        showpage(htmlPath)
-    return htmlPath
-
-def tagreplace(sourcestr, colors=lite, markup='xhtml', 
-               linenumbers=0, dosheet=1, tagstart='<PY>'.lower(),
-               tagend='</PY>'.lower(), stylesheet='pystyle.css'):
-    """This is a helper function for pageconvert. Returns css, page.
-    """
-    if markup.lower() != 'html':
-        link  = '<link rel="stylesheet" href="%s" type="text/css"/></head>'
-        css = link%stylesheet
-        if sourcestr.find(css) == -1:
-            sourcestr = sourcestr.replace('</head>', css, 1)
-    starttags = sourcestr.count(tagstart)
-    endtags = sourcestr.count(tagend)
-    if starttags:
-        if starttags == endtags:
-            for _ in range(starttags):
-               datastart = sourcestr.find(tagstart)
-               dataend = sourcestr.find(tagend)
-               data = sourcestr[datastart+len(tagstart):dataend]
-               data = unescape(data)
-               css , data = str2markup(data, colors=colors, 
-                         linenumbers=linenumbers, markup=markup, form='embed')
-               start = sourcestr[:datastart]
-               end = sourcestr[dataend+len(tagend):]
-               sourcestr =  ''.join([start,data,end])
-        else:
-            raise InputError,'Tag mismatch!\nCheck %s,%s tags'%tagstart,tagend
-    if not dosheet:
-        css = None
-    return css, sourcestr
-    
-def pageconvert(path, out=None, colors=lite, markup='xhtml', linenumbers=0,
-                  dosheet=1, tagstart='<PY>'.lower(), tagend='</PY>'.lower(),
-                  stylesheet='pystyle', show=1, returnstr=0):
-    """This function can colorize Python source
-
-       that is written in a webpage enclosed in tags.
-    """
-    if out == None:
-        out = os.path.dirname(path)
-    infile = open(path, 'r').read()
-    css,page  = tagreplace(sourcestr=infile,colors=colors, 
-                   markup=markup, linenumbers=linenumbers, dosheet=dosheet,
-                   tagstart=tagstart, tagend=tagend, stylesheet=stylesheet)
-    if not returnstr:
-        newpath = os.path.abspath(os.path.join(
-                  out,'tmp', os.path.basename(path)))
-        if not os.path.exists(newpath):
-            try:
-                os.makedirs(os.path.dirname(newpath))
-            except:
-                pass#traceback.print_exc()
-                #Usage()
-        y = open(newpath, 'w')
-        y.write(page)
-        y.close()
-        if css:
-            csspath = os.path.abspath(os.path.join(
-                      out,'tmp','%s.css'%stylesheet))
-            x = open(csspath,'w')
-            x.write(css)
-            x.close()
-        if show:
-            try:
-                os.startfile(newpath)
-            except:
-                traceback.print_exc()
-        return newpath
-    else:
-        return css, page
-
-##################################################################### helpers
-
-def walkdir(dir):
-    """Return a list of .py and .pyw files from a given directory.
-
-       This function can be written as a generator Python 2.3, or a genexp
-       in Python 2.4. But 2.2 and 2.1 would be left out....
-    """
-    # Get a list of files that match *.py*
-    GLOB_PATTERN = os.path.join(dir, "*.[p][y]*")
-    pathlist = glob.glob(GLOB_PATTERN)
-    # Now filter out all but py and pyw
-    filterlist = [x for x in pathlist
-                        if x.endswith('.py')
-                        or x.endswith('.pyw')]
-    if filterlist != []:
-        # if we have a list send it
-        return filterlist
-    else:
-        return None
-
-def showpage(path):
-    """Helper function to open webpages"""
-    try:
-        import webbrowser
-        webbrowser.open_new(os.path.abspath(path))
-    except:
-        traceback.print_exc()
-
-def _printinfo(message, quiet):
-    """Helper to print messages"""
-    if not quiet:
-        print message
-
-def escape(text):
-     """escape text for html. similar to cgi.escape"""
-     text = text.replace("&", "&amp;")
-     text = text.replace("<", "&lt;")
-     text = text.replace(">", "&gt;")
-     return text
-
-def unescape(text):
-     """unsecape escaped text"""
-     text = text.replace("&quot;", '"')
-     text = text.replace("&gt;", ">")
-     text = text.replace("&lt;", "<")
-     text = text.replace("&amp;", "&")
-     return text
-
-########################################################### Custom Exceptions
-
-class PySourceColorError(Exception):
-    # Base for custom errors
-    def __init__(self, msg=''):
-        self._msg = msg
-        Exception.__init__(self, msg)
-    def __repr__(self):
-        return self._msg
-    __str__ = __repr__
-
-class PathError(PySourceColorError):
-    def __init__(self, msg):
-       PySourceColorError.__init__(self,
-         'Path error! : %s'% msg)
-
-class InputError(PySourceColorError):
-   def __init__(self, msg):
-       PySourceColorError.__init__(self,
-         'Input error! : %s'% msg)
-
-########################################################## Python code parser
-
-class Parser(object):
-
-    """MoinMoin python parser heavily chopped :)"""
-
-    def __init__(self, raw, colors=None, title='', out=sys.stdout,
-                   markup='html', header=None, footer=None, linenumbers=0):
-        """Store the source text & set some flags"""
-        if colors == None:
-            colors = defaultColors
-        self.raw = raw.expandtabs().rstrip()
-        self.title = os.path.basename(title)
-        self.out = out
-        self.line = ''
-        self.lasttext = ''
-        self.argFlag = 0
-        self.classFlag = 0
-        self.defFlag = 0
-        self.decoratorFlag = 0
-        self.external = 0
-        self.markup = markup.upper()
-        self.colors = colors
-        self.header = header
-        self.footer = footer
-        self.doArgs = 1 #  overrides the new tokens
-        self.doNames = 1 #  overrides the new tokens
-        self.doMathOps = 1 #  overrides the new tokens
-        self.doBrackets = 1 #  overrides the new tokens
-        self.doURL = 1 # override url conversion
-        self.LINENUMHOLDER = "___line___".upper()
-        self.LINESTART = "___start___".upper()
-        self.skip = 0
-        # add space left side of code for padding.Override in color dict.
-        self.extraspace = self.colors.get(EXTRASPACE, '')
-        # Linenumbers less then zero also have numberlinks
-        self.dolinenums = self.linenum = abs(linenumbers)
-        if linenumbers < 0:
-            self.numberlinks = 1
-        else:
-            self.numberlinks = 0
-
-    def format(self, form=None):
-        """Parse and send the colorized source"""
-        if form in ('snip','code'):
-            self.addEnds = 0
-        elif form == 'embed':
-            self.addEnds = 0
-            self.external = 1
-        else:
-            if form == 'external':
-                self.external = 1
-            self.addEnds = 1
-
-        # Store line offsets in self.lines
-        self.lines = [0, 0]
-        pos = 0
-
-        # Add linenumbers
-        if self.dolinenums:
-            start=self.LINENUMHOLDER+' '+self.extraspace
-        else:
-            start=''+self.extraspace
-        newlines = []
-        lines = self.raw.splitlines(0)
-        for l in lines:
-             # span and div escape for customizing and embedding raw text 
-             if (l.startswith('#$#')
-                  or l.startswith('#%#')
-                  or l.startswith('#@#')):   
-                newlines.append(l)
-             else:
-                # kludge for line spans in css,xhtml
-                if self.markup in ['XHTML','CSS']:
-                    newlines.append(self.LINESTART+' '+start+l)
-                else:
-                    newlines.append(start+l)
-        self.raw = "\n".join(newlines)+'\n'# plus an extra newline at the end
-
-        # Gather lines
-        while 1:
-            pos = self.raw.find('\n', pos) + 1
-            if not pos: break
-            self.lines.append(pos)
-        self.lines.append(len(self.raw))
-
-        # Wrap text in a filelike object
-        self.pos = 0
-        text = StringIO.StringIO(self.raw)
-        
-        # Markup start
-        if self.addEnds:
-            self._doPageStart()
-        else:
-            self._doSnippetStart()
-
-        ## Tokenize calls the __call__
-        ## function for each token till done.
-        # Parse the source and write out the results.
-        try:
-            tokenize.tokenize(text.readline, self)
-        except tokenize.TokenError, ex:
-            msg = ex[0]
-            line = ex[1][0]
-            self.out.write("<h3>ERROR: %s</h3>%s\n"%
-                            (msg, self.raw[self.lines[line]:]))
-            #traceback.print_exc()
-
-        # Markup end
-        if self.addEnds:
-            self._doPageEnd()
-        else:
-            self._doSnippetEnd()
-
-    def __call__(self, toktype, toktext, (srow,scol), (erow,ecol), line):
-        """Token handler. Order is important do not rearrange."""
-        self.line = line
-        # Calculate new positions
-        oldpos = self.pos
-        newpos = self.lines[srow] + scol
-        self.pos = newpos + len(toktext)
-        # Handle newlines
-        if toktype in (token.NEWLINE, tokenize.NL):
-            self.decoratorFlag = self.argFlag = 0
-            # kludge for line spans in css,xhtml
-            if self.markup in ['XHTML','CSS']:
-                self.out.write('</span>')
-            self.out.write('\n')
-            return
-
-        # Send the original whitespace, and tokenize backslashes if present.
-        # Tokenizer.py just sends continued line backslashes with whitespace.
-        # This is a hack to tokenize continued line slashes as operators.
-        # Should continued line backslashes be treated as operators
-        # or some other token?
-
-        if newpos > oldpos:
-            if self.raw[oldpos:newpos].isspace():
-                # consume a single space after linestarts and linenumbers
-                # had to have them so tokenizer could seperate them.
-                # multiline strings are handled by do_Text functions
-                if self.lasttext != self.LINESTART \
-                        and self.lasttext != self.LINENUMHOLDER:
-                    self.out.write(self.raw[oldpos:newpos])
-                else:
-                    self.out.write(self.raw[oldpos+1:newpos])
-            else:
-                slash = self.raw[oldpos:newpos].find('\\')+oldpos
-                self.out.write(self.raw[oldpos:slash])
-                getattr(self, '_send%sText'%(self.markup))(OPERATOR, '\\')
-                self.linenum+=1
-                # kludge for line spans in css,xhtml
-                if self.markup in ['XHTML','CSS']:
-                    self.out.write('</span>')
-                self.out.write(self.raw[slash+1:newpos])
-
-        # Skip indenting tokens
-        if toktype in (token.INDENT, token.DEDENT):
-            self.pos = newpos
-            return
-
-        # Look for operators
-        if token.LPAR <= toktype and toktype <= token.OP:
-            # Trap decorators py2.4 >
-            if toktext == '@':
-                toktype = DECORATOR
-                # Set a flag if this was the decorator start so
-                # the decorator name and arguments can be identified
-                self.decoratorFlag = self.argFlag = 1
-            else:
-                if self.doArgs:
-                    # Find the start for arguments
-                    if toktext == '(' and self.argFlag:
-                        self.argFlag = 2
-                    # Find the end for arguments
-                    elif toktext == ':':
-                        self.argFlag = 0
-                ## Seperate the diffrent operator types
-                # Brackets
-                if self.doBrackets and toktext in ['[',']','(',')','{','}']:
-                    toktype = BRACKETS
-                # Math operators 
-                elif self.doMathOps and toktext in ['*=','**=','-=','+=','|=',
-                                                      '%=','>>=','<<=','=','^=',
-                                                      '/=', '+','-','**','*','/','%']:
-                    toktype = MATH_OPERATOR
-                # Operator 
-                else:
-                    toktype = OPERATOR
-                    # example how flags should work.
-                    # def fun(arg=argvalue,arg2=argvalue2):
-                    # 0   1  2 A 1   N    2 A  1    N     0
-                    if toktext == "=" and self.argFlag == 2:
-                         self.argFlag = 1
-                    elif toktext == "," and self.argFlag == 1:
-                        self.argFlag = 2
-        # Look for keywords
-        elif toktype == NAME and keyword.iskeyword(toktext):
-            toktype = KEYWORD
-            # Set a flag if this was the class / def start so
-            # the class / def name and arguments can be identified
-            if toktext in ['class', 'def']:
-                if toktext =='class' and \
-                         not line[:line.find('class')].endswith('.'): 
-                    self.classFlag = self.argFlag = 1
-                elif toktext == 'def' and \
-                         not line[:line.find('def')].endswith('.'):
-                    self.defFlag = self.argFlag = 1
-                else:
-                    # must have used a keyword as a name i.e. self.class
-                    toktype = ERRORTOKEN 
-
-        # Look for class, def, decorator name
-        elif (self.classFlag or self.defFlag or self.decoratorFlag) \
-                and self.doNames:
-            if self.classFlag:
-                self.classFlag = 0
-                toktype = CLASS_NAME
-            elif self.defFlag:
-                self.defFlag = 0
-                toktype = DEF_NAME
-            elif self.decoratorFlag:
-                self.decoratorFlag = 0
-                toktype = DECORATOR_NAME
-
-        # Look for strings
-        # Order of evaluation is important do not change.
-        elif toktype == token.STRING:
-            text = toktext.lower()
-            # TRIPLE DOUBLE QUOTE's
-            if (text[:3] == '"""'):
-                toktype = TRIPLEDOUBLEQUOTE
-            elif (text[:4] == 'r"""'):
-                toktype = TRIPLEDOUBLEQUOTE_R
-            elif (text[:4] == 'u"""' or
-                   text[:5] == 'ur"""'):
-                toktype = TRIPLEDOUBLEQUOTE_U
-            # DOUBLE QUOTE's
-            elif (text[:1] == '"'):
-                toktype = DOUBLEQUOTE
-            elif (text[:2] == 'r"'):
-                toktype = DOUBLEQUOTE_R
-            elif (text[:2] == 'u"' or
-                   text[:3] == 'ur"'):
-                toktype = DOUBLEQUOTE_U
-            # TRIPLE SINGLE QUOTE's
-            elif (text[:3] == "'''"):
-                 toktype = TRIPLESINGLEQUOTE
-            elif (text[:4] == "r'''"):
-                toktype = TRIPLESINGLEQUOTE_R
-            elif (text[:4] == "u'''" or
-                   text[:5] == "ur'''"):
-                toktype = TRIPLESINGLEQUOTE_U
-            # SINGLE QUOTE's
-            elif (text[:1] == "'"):
-                toktype = SINGLEQUOTE
-            elif (text[:2] == "r'"):
-                toktype = SINGLEQUOTE_R
-            elif (text[:2] == "u'" or
-                   text[:3] == "ur'"):
-                toktype = SINGLEQUOTE_U
-
-            # test for invalid string declaration
-            if self.lasttext.lower() == 'ru':
-                toktype = ERRORTOKEN
-           
-        # Look for comments
-        elif toktype == COMMENT:
-            if toktext[:2] == "##":
-                toktype = DOUBLECOMMENT
-            elif toktext[:3] == '#$#':
-                toktype = TEXT
-                self.textFlag = 'SPAN'
-                toktext = toktext[3:]
-            elif toktext[:3] == '#%#':
-                toktype = TEXT
-                self.textFlag = 'DIV'
-                toktext = toktext[3:]
-            elif toktext[:3] == '#@#':
-                toktype = TEXT
-                self.textFlag = 'RAW'
-                toktext = toktext[3:]
-            if self.doURL:
-                # this is a 'fake helper function'
-                # url(URI,Alias_name) or url(URI)
-                url_pos = toktext.find('url(')
-                if url_pos != -1:
-                    before = toktext[:url_pos]
-                    url = toktext[url_pos+4:]
-                    splitpoint = url.find(',')
-                    endpoint = url.find(')')
-                    after = url[endpoint+1:]
-                    url = url[:endpoint]
-                    if splitpoint != -1:
-                        urlparts = url.split(',',1)
-                        toktext = '%s<a href="%s">%s</a>%s'%(
-                                   before,urlparts[0],urlparts[1].lstrip(),after) 
-                    else:
-                        toktext = '%s<a href="%s">%s</a>%s'%(before,url,url,after) 
-                        
-        # Seperate errors from decorators
-        elif toktype == ERRORTOKEN:
-            # Bug fix for < py2.4
-            # space between decorators
-            if self.argFlag and toktext.isspace():
-                #toktype = NAME
-                self.out.write(toktext)
-                return
-            # Bug fix for py2.2 linenumbers with decorators
-            elif toktext.isspace():
-                # What if we have a decorator after a >>> or ...
-                #p = line.find('@')
-                #if p >= 0 and not line[:p].isspace():
-                    #self.out.write(toktext)
-                    #return
-                if self.skip:
-                    self.skip=0
-                    return
-                else:           
-                    self.out.write(toktext)
-                    return
-            # trap decorators < py2.4
-            elif toktext == '@':
-                toktype = DECORATOR
-                # Set a flag if this was the decorator start so
-                # the decorator name and arguments can be identified
-                self.decoratorFlag = self.argFlag = 1
-
-        # Seperate args from names
-        elif (self.argFlag == 2 and
-              toktype == NAME and
-              toktext != 'None' and
-              self.doArgs):
-            toktype = ARGS
-
-        # Look for line numbers
-        # The conversion code for them is in the send_text functions.
-        if toktext in [self.LINENUMHOLDER,self.LINESTART]:
-            toktype = LINENUMBER
-            # if we don't have linenumbers set flag
-            # to skip the trailing space from linestart
-            if toktext == self.LINESTART and not self.dolinenums \
-                                or toktext == self.LINENUMHOLDER:
-                self.skip=1
-
-
-        # Skip blank token that made it thru
-        ## bugfix for the last empty tag.
-        if toktext == '':
-            return
-
-        # Last token text history
-        self.lasttext = toktext
-        
-        # escape all but the urls in the comments
-        if toktype in (DOUBLECOMMENT, COMMENT):
-            if toktext.find('<a href=') == -1:
-                toktext = escape(toktext)
-            else:
-                pass
-        elif toktype == TEXT:
-            pass
-        else:
-            toktext = escape(toktext)
-
-        # Send text for any markup
-        getattr(self, '_send%sText'%(self.markup))(toktype, toktext)
-        return
-
-    ################################################################# Helpers
-
-    def _doSnippetStart(self):
-        if self.markup == 'HTML':
-            # Start of html snippet
-            self.out.write('<pre>\n')
-        else:
-            # Start of css/xhtml snippet
-            self.out.write(self.colors.get(CODESTART,'<pre class="py">\n'))
-
-    def _doSnippetEnd(self):
-        # End of html snippet
-        self.out.write(self.colors.get(CODEEND,'</pre>\n'))
-
-    ######################################################## markup selectors
-
-    def _getFile(self, filepath): 
-        try:
-            _file = open(filepath,'r')
-            content = _file.read()
-            _file.close()
-        except:
-            traceback.print_exc()
-            content = ''
-        return content
-
-    def _doPageStart(self):
-        getattr(self, '_do%sStart'%(self.markup))()
-
-    def _doPageHeader(self):
-        if self.header != None:
-            if self.header.find('#$#') != -1 or \
-                self.header.find('#$#') != -1 or \
-                self.header.find('#%#') != -1:
-                self.out.write(self.header[3:])
-            else:
-                if self.header != '':
-                    self.header = self._getFile(self.header)
-                getattr(self, '_do%sHeader'%(self.markup))()
-
-    def _doPageFooter(self):
-        if self.footer != None:
-            if self.footer.find('#$#') != -1 or \
-                self.footer.find('#@#') != -1 or \
-                self.footer.find('#%#') != -1:
-                self.out.write(self.footer[3:])
-            else:
-                if self.footer != '':
-                    self.footer = self._getFile(self.footer)
-                getattr(self, '_do%sFooter'%(self.markup))()
-
-    def _doPageEnd(self):
-        getattr(self, '_do%sEnd'%(self.markup))()
-
-    ################################################### color/style retrieval
-    ## Some of these are not used anymore but are kept for documentation
-
-    def _getLineNumber(self):
-        num = self.linenum
-        self.linenum+=1
-        return  str(num).rjust(5)+" "
-
-    def _getTags(self, key):
-        # style tags
-        return self.colors.get(key, self.colors[NAME])[0]
-
-    def _getForeColor(self, key):
-        # get text foreground color, if not set to black
-        color = self.colors.get(key, self.colors[NAME])[1]
-        if color[:1] != '#':
-            color = '#000000'
-        return color
-
-    def _getBackColor(self, key):
-        # get text background color
-        return self.colors.get(key, self.colors[NAME])[2]
-
-    def _getPageColor(self):
-        # get page background color
-        return self.colors.get(PAGEBACKGROUND, '#FFFFFF')
-
-    def _getStyle(self, key):
-        # get the token style from the color dictionary
-        return self.colors.get(key, self.colors[NAME])
-
-    def _getMarkupClass(self, key):
-        # get the markup class name from the markup dictionary
-        return MARKUPDICT.get(key, MARKUPDICT[NAME])
-
-    def _getDocumentCreatedBy(self):
-        return '<!--This document created by %s ver.%s on: %s-->\n'%(
-                  __title__,__version__,time.ctime())
-
-    ################################################### HTML markup functions
-
-    def _doHTMLStart(self):
-        # Start of html page
-        self.out.write('<!DOCTYPE html PUBLIC \
-"-//W3C//DTD HTML 4.01//EN">\n')
-        self.out.write('<html><head><title>%s</title>\n'%(self.title))
-        self.out.write(self._getDocumentCreatedBy())
-        self.out.write('<meta http-equiv="Content-Type" \
-content="text/html;charset=iso-8859-1">\n')
-        # Get background
-        self.out.write('</head><body bgcolor="%s">\n'%self._getPageColor())
-        self._doPageHeader()
-        self.out.write('<pre>')
-
-    def _getHTMLStyles(self, toktype, toktext):
-        # Get styles
-        tags, color = self.colors.get(toktype, self.colors[NAME])[:2]#
-        tagstart=[]
-        tagend=[]
-        # check for styles and set them if needed.
-        if 'b' in tags:#Bold
-            tagstart.append('<b>')
-            tagend.append('</b>')
-        if 'i' in tags:#Italics
-            tagstart.append('<i>')
-            tagend.append('</i>')
-        if 'u' in tags:#Underline
-            tagstart.append('<u>')
-            tagend.append('</u>')
-        # HTML tags should be paired like so : <b><i><u>Doh!</u></i></b>
-        tagend.reverse()
-        starttags="".join(tagstart)
-        endtags="".join(tagend)
-        return starttags,endtags,color
-
-    def _sendHTMLText(self, toktype, toktext):
-        numberlinks = self.numberlinks
-        
-        # If it is an error, set a red box around the bad tokens
-        # older browsers should ignore it
-        if toktype == ERRORTOKEN:
-            style = ' style="border: solid 1.5pt #FF0000;"'
-        else:
-            style = ''
-        # Get styles
-        starttag, endtag, color = self._getHTMLStyles(toktype, toktext)
-        # This is a hack to 'fix' multi-line  strings.
-        # Multi-line strings are treated as only one token 
-        # even though they can be several physical lines.
-        # That makes it hard to spot the start of a line,
-        # because at this level all we know about are tokens.
-        
-        if toktext.count(self.LINENUMHOLDER):
-            # rip apart the string and separate it by line.
-            # count lines and change all linenum token to line numbers.
-            # embedded all the new font tags inside the current one.
-            # Do this by ending the tag first then writing our new tags,
-            # then starting another font tag exactly like the first one.
-            if toktype == LINENUMBER:
-                splittext = toktext.split(self.LINENUMHOLDER)
-            else:    
-                splittext = toktext.split(self.LINENUMHOLDER+' ')
-            store = []
-            store.append(splittext.pop(0))
-            lstarttag, lendtag, lcolor = self._getHTMLStyles(LINENUMBER, toktext)
-            count = len(splittext)
-            for item in splittext:
-                num =  self._getLineNumber()
-                if numberlinks:
-                    numstrip = num.strip()
-                    content = '<a name="%s" href="#%s">%s</a>' \
-                              %(numstrip,numstrip,num)
-                else:
-                    content = num
-                if count <= 1:
-                    endtag,starttag = '',''
-                linenumber = ''.join([endtag,'<font color=', lcolor, '>',
-                            lstarttag, content, lendtag, '</font>' ,starttag])
-                store.append(linenumber+item)
-            toktext = ''.join(store)
-        # send text
-        ## Output optimization
-        # skip font tag if black text, but styles will still be sent. (b,u,i)
-        if color !='#000000':
-            startfont = '<font color="%s"%s>'%(color, style)
-            endfont = '</font>'
-        else:
-            startfont, endfont = ('','')
-        if toktype != LINENUMBER:
-            self.out.write(''.join([startfont,starttag,
-                                     toktext,endtag,endfont]))
-        else:
-            self.out.write(toktext)
-        return
-
-    def _doHTMLHeader(self):
-        # Optional
-        if self.header != '':
-            self.out.write('%s\n'%self.header)
-        else:
-            color = self._getForeColor(NAME)
-            self.out.write('<b><font color="%s"># %s \
-                            <br># %s</font></b><hr>\n'%
-                           (color, self.title, time.ctime()))
-
-    def _doHTMLFooter(self):
-        # Optional
-        if self.footer != '':
-            self.out.write('%s\n'%self.footer)
-        else:
-            color = self._getForeColor(NAME)
-            self.out.write('<b><font color="%s"> \
-                            <hr># %s<br># %s</font></b>\n'%
-                           (color, self.title, time.ctime()))
-
-    def _doHTMLEnd(self):
-        # End of html page
-        self.out.write('</pre>\n')
-        # Write a little info at the bottom
-        self._doPageFooter()
-        self.out.write('</body></html>\n')
-
-    #################################################### CSS markup functions
-
-    def _getCSSStyle(self, key):
-        # Get the tags and colors from the dictionary
-        tags, forecolor, backcolor = self._getStyle(key)
-        style=[]
-        border = None
-        bordercolor = None
-        tags = tags.lower()
-        if tags:
-            # get the border color if specified
-            # the border color will be appended to
-            # the list after we define a border
-            if '#' in tags:# border color 
-                start = tags.find('#')
-                end = start + 7
-                bordercolor = tags[start:end]
-                tags.replace(bordercolor,'',1)
-            # text styles
-            if 'b' in tags:# Bold
-                style.append('font-weight:bold;')
-            else:
-                style.append('font-weight:normal;')    
-            if 'i' in tags:# Italic
-                style.append('font-style:italic;')
-            if 'u' in tags:# Underline
-                style.append('text-decoration:underline;')
-            # border size
-            if 'l' in tags:# thick border
-                size='thick'
-            elif 'm' in tags:# medium border
-                size='medium'
-            elif 't' in tags:# thin border
-                size='thin'
-            else:# default
-                size='medium'
-            # border styles
-            if 'n' in tags:# inset border
-                border='inset'
-            elif 'o' in tags:# outset border
-                border='outset'
-            elif 'r' in tags:# ridge border
-                border='ridge'
-            elif 'g' in tags:# groove border
-                border='groove'
-            elif '=' in tags:# double border
-                border='double'
-            elif '.' in tags:# dotted border
-                border='dotted'
-            elif '-' in tags:# dashed border
-                border='dashed'
-            elif 's' in tags:# solid border 
-                border='solid'
-            # border type check
-            seperate_sides=0
-            for side in ['<','>','^','v']:
-                if side in tags:
-                    seperate_sides+=1
-            # border box or seperate sides
-            if seperate_sides==0 and border:
-                    style.append('border: %s %s;'%(border,size))
-            else:
-                if border == None:
-                   border = 'solid'
-                if 'v' in tags:# bottom border
-                    style.append('border-bottom:%s %s;'%(border,size))
-                if '<' in tags:# left border
-                    style.append('border-left:%s %s;'%(border,size))
-                if '>' in tags:# right border
-                    style.append('border-right:%s %s;'%(border,size))
-                if '^' in tags:# top border
-                    style.append('border-top:%s %s;'%(border,size))
-        else:
-            style.append('font-weight:normal;')# css inherited style fix    
-        # we have to define our borders before we set colors
-        if bordercolor:
-            style.append('border-color:%s;'%bordercolor)
-        # text forecolor  
-        style.append('color:%s;'% forecolor)
-        # text backcolor
-        if backcolor:
-            style.append('background-color:%s;'%backcolor)
-        return (self._getMarkupClass(key),' '.join(style))
-
-    def _sendCSSStyle(self, external=0):
-        """ create external and internal style sheets"""
-        styles = []
-        external += self.external
-        if not external:
-            styles.append('<style type="text/css">\n<!--\n')
-        # Get page background color and write styles ignore any we don't know
-        styles.append('body { background:%s; }\n'%self._getPageColor())
-        # write out the various css styles
-        for key in MARKUPDICT:
-            styles.append('.%s { %s }\n'%self._getCSSStyle(key))
-        # If you want to style the pre tag you must modify the color dict.
-        #  Example: 
-        #  lite[PY] = .py {border: solid thin #000000;background:#555555}\n''' 
-        styles.append(self.colors.get(PY, '.py { }\n'))
-        # Extra css can be added here
-        # add CSSHOOK to the color dict if you need it.
-        # Example: 
-        #lite[CSSHOOK] = """.mytag { border: solid thin #000000; } \n
-        #                   .myothertag { font-weight:bold; )\n"""
-        styles.append(self.colors.get(CSSHOOK,''))
-        if not self.external:
-             styles.append('--></style>\n')
-        return ''.join(styles)
-
-    def _doCSSStart(self):
-        # Start of css/html 4.01 page
-        self.out.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">\n')
-        self.out.write('<html><head><title>%s</title>\n'%(self.title))
-        self.out.write(self._getDocumentCreatedBy())
-        self.out.write('<meta http-equiv="Content-Type" \
-content="text/html;charset=iso-8859-1">\n')
-        self._doCSSStyleSheet()
-        self.out.write('</head>\n<body>\n')
-        # Write a little info at the top.
-        self._doPageHeader()
-        self.out.write(self.colors.get(CODESTART,'<pre class="py">\n'))
-        return
-
-    def _doCSSStyleSheet(self):
-        if not self.external:
-            # write an embedded style sheet
-            self.out.write(self._sendCSSStyle())
-        else:
-            # write a link to an external style sheet
-            self.out.write('<link rel="stylesheet" \
-href="pystyle.css" type="text/css">')
-        return
-
-    def _sendCSSText(self, toktype, toktext):
-        # This is a hack to 'fix' multi-line strings.
-        # Multi-line strings are treated as only one token 
-        # even though they can be several physical lines.
-        # That makes it hard to spot the start of a line,
-        # because at this level all we know about are tokens.
-        markupclass = MARKUPDICT.get(toktype, MARKUPDICT[NAME])
-        # if it is a LINENUMBER type then we can skip the rest
-        if toktext == self.LINESTART and toktype == LINENUMBER:
-            self.out.write('<span class="py_line">')
-            return
-        if toktext.count(self.LINENUMHOLDER):
-            # rip apart the string and separate it by line
-            # count lines and change all linenum token to line numbers
-            # also convert linestart and lineend tokens
-            # <linestart> <lnumstart> lnum <lnumend> text <lineend>
-            #################################################
-            newmarkup = MARKUPDICT.get(LINENUMBER, MARKUPDICT[NAME])
-            lstartspan = '<span class="%s">'%(newmarkup)
-            if toktype == LINENUMBER:
-                splittext = toktext.split(self.LINENUMHOLDER)
-            else:    
-                splittext = toktext.split(self.LINENUMHOLDER+' ')
-            store = []
-            # we have already seen the first linenumber token
-            # so we can skip the first one
-            store.append(splittext.pop(0))
-            for item in splittext:
-                num = self._getLineNumber()
-                if self.numberlinks:
-                    numstrip = num.strip()
-                    content= '<a name="%s" href="#%s">%s</a>' \
-                              %(numstrip,numstrip,num)
-                else:
-                    content = num
-                linenumber= ''.join([lstartspan,content,'</span>'])
-                store.append(linenumber+item)
-            toktext = ''.join(store)
-        if toktext.count(self.LINESTART):
-            # wraps the textline in a line span
-            # this adds a lot of kludges, is it really worth it?
-            store = []
-            parts = toktext.split(self.LINESTART+' ')
-            # handle the first part differently
-            # the whole token gets wraqpped in a span later on
-            first = parts.pop(0)
-            # place spans before the newline
-            pos = first.rfind('\n')
-            if pos != -1:
-                first=first[:pos]+'</span></span>'+first[pos:]
-            store.append(first)
-            #process the rest of the string
-            for item in parts:
-                #handle line numbers if present
-                if self.dolinenums:
-                    item = item.replace('</span>',
-                           '</span><span class="%s">'%(markupclass))
-                else:
-                    item = '<span class="%s">%s'%(markupclass,item)
-                # add endings for line and string tokens
-                pos = item.rfind('\n')
-                if pos != -1:
-                    item=item[:pos]+'</span></span>\n'
-                store.append(item)
-            # add start tags for lines
-            toktext = '<span class="py_line">'.join(store)
-        # Send text
-        if toktype != LINENUMBER:
-            if toktype == TEXT and self.textFlag == 'DIV':
-                startspan = '<div class="%s">'%(markupclass)
-                endspan = '</div>'
-            elif toktype == TEXT and self.textFlag == 'RAW': 
-                startspan,endspan = ('','')
-            else:
-                startspan = '<span class="%s">'%(markupclass)
-                endspan = '</span>'
-            self.out.write(''.join([startspan, toktext, endspan]))
-        else:
-            self.out.write(toktext)
-        return
-
-    def _doCSSHeader(self):
-        if self.header != '':
-            self.out.write('%s\n'%self.header)
-        else:
-            name = MARKUPDICT.get(NAME)
-            self.out.write('<div class="%s"># %s <br> \
-# %s</div><hr>\n'%(name, self.title, time.ctime()))
-
-    def _doCSSFooter(self):
-        # Optional
-        if self.footer != '':
-            self.out.write('%s\n'%self.footer)
-        else:
-            self.out.write('<hr><div class="%s"># %s <br> \
-# %s</div>\n'%(MARKUPDICT.get(NAME),self.title, time.ctime()))
-
-    def _doCSSEnd(self):
-        # End of css/html page
-        self.out.write(self.colors.get(CODEEND,'</pre>\n'))
-        # Write a little info at the bottom
-        self._doPageFooter()
-        self.out.write('</body></html>\n')
-        return
-
-    ################################################## XHTML markup functions
-
-    def _doXHTMLStart(self):
-        # XHTML is really just XML + HTML 4.01.
-        # We only need to change the page headers, 
-        # and a few tags to get valid XHTML.
-        # Start of xhtml page
-        self.out.write('<?xml version="1.0"?>\n \
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"\n \
-    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">\n \
-<html xmlns="http://www.w3.org/1999/xhtml">\n')
-        self.out.write('<head><title>%s</title>\n'%(self.title))
-        self.out.write(self._getDocumentCreatedBy())
-        self.out.write('<meta http-equiv="Content-Type" \
-content="text/html;charset=iso-8859-1"/>\n')
-        self._doXHTMLStyleSheet()
-        self.out.write('</head>\n<body>\n')
-        # Write a little info at the top.
-        self._doPageHeader()
-        self.out.write(self.colors.get(CODESTART,'<pre class="py">\n'))
-        return
-
-    def _doXHTMLStyleSheet(self):
-        if not self.external:
-            # write an embedded style sheet
-            self.out.write(self._sendCSSStyle())
-        else:
-            # write a link to an external style sheet
-            self.out.write('<link rel="stylesheet" \
-href="pystyle.css" type="text/css"/>\n')
-        return
-
-    def _sendXHTMLText(self, toktype, toktext):
-        self._sendCSSText(toktype, toktext)
-
-    def _doXHTMLHeader(self):
-        # Optional
-        if self.header:
-            self.out.write('%s\n'%self.header)
-        else:
-            name = MARKUPDICT.get(NAME)
-            self.out.write('<div class="%s"># %s <br/> \
-# %s</div><hr/>\n '%(
-            name, self.title, time.ctime()))
-
-    def _doXHTMLFooter(self):
-        # Optional
-        if self.footer:
-            self.out.write('%s\n'%self.footer)
-        else:
-            self.out.write('<hr/><div class="%s"># %s <br/> \
-# %s</div>\n'%(MARKUPDICT.get(NAME), self.title, time.ctime()))
-
-    def _doXHTMLEnd(self):
-        self._doCSSEnd()
-
-#############################################################################
-
-if __name__ == '__main__':
-    cli()
-
-#############################################################################
-# PySourceColor.py
-# 2004, 2005 M.E.Farmer Jr.
-# Python license
diff --git a/lib/paste/util/UserDict24.py b/lib/paste/util/UserDict24.py
@@ -1,167 +0,0 @@
-"""A more or less complete user-defined wrapper around dictionary objects."""
-
-class UserDict:
-    def __init__(self, dict=None, **kwargs):
-        self.data = {}
-        if dict is not None:
-            if not hasattr(dict,'keys'):
-                dict = type({})(dict)   # make mapping from a sequence
-            self.update(dict)
-        if len(kwargs):
-            self.update(kwargs)
-    def __repr__(self): return repr(self.data)
-    def __cmp__(self, dict):
-        if isinstance(dict, UserDict):
-            return cmp(self.data, dict.data)
-        else:
-            return cmp(self.data, dict)
-    def __len__(self): return len(self.data)
-    def __getitem__(self, key): return self.data[key]
-    def __setitem__(self, key, item): self.data[key] = item
-    def __delitem__(self, key): del self.data[key]
-    def clear(self): self.data.clear()
-    def copy(self):
-        if self.__class__ is UserDict:
-            return UserDict(self.data)
-        import copy
-        data = self.data
-        try:
-            self.data = {}
-            c = copy.copy(self)
-        finally:
-            self.data = data
-        c.update(self)
-        return c
-    def keys(self): return self.data.keys()
-    def items(self): return self.data.items()
-    def iteritems(self): return self.data.iteritems()
-    def iterkeys(self): return self.data.iterkeys()
-    def itervalues(self): return self.data.itervalues()
-    def values(self): return self.data.values()
-    def has_key(self, key): return self.data.has_key(key)
-    def update(self, dict):
-        if isinstance(dict, UserDict):
-            self.data.update(dict.data)
-        elif isinstance(dict, type(self.data)):
-            self.data.update(dict)
-        else:
-            for k, v in dict.items():
-                self[k] = v
-    def get(self, key, failobj=None):
-        if not self.has_key(key):
-            return failobj
-        return self[key]
-    def setdefault(self, key, failobj=None):
-        if not self.has_key(key):
-            self[key] = failobj
-        return self[key]
-    def pop(self, key, *args):
-        return self.data.pop(key, *args)
-    def popitem(self):
-        return self.data.popitem()
-    def __contains__(self, key):
-        return key in self.data
-    def fromkeys(cls, iterable, value=None):
-        d = cls()
-        for key in iterable:
-            d[key] = value
-        return d
-    fromkeys = classmethod(fromkeys)
-
-class IterableUserDict(UserDict):
-    def __iter__(self):
-        return iter(self.data)
-
-class DictMixin:
-    # Mixin defining all dictionary methods for classes that already have
-    # a minimum dictionary interface including getitem, setitem, delitem,
-    # and keys. Without knowledge of the subclass constructor, the mixin
-    # does not define __init__() or copy().  In addition to the four base
-    # methods, progressively more efficiency comes with defining
-    # __contains__(), __iter__(), and iteritems().
-
-    # second level definitions support higher levels
-    def __iter__(self):
-        for k in self.keys():
-            yield k
-    def has_key(self, key):
-        try:
-            value = self[key]
-        except KeyError:
-            return False
-        return True
-    def __contains__(self, key):
-        return self.has_key(key)
-
-    # third level takes advantage of second level definitions
-    def iteritems(self):
-        for k in self:
-            yield (k, self[k])
-    def iterkeys(self):
-        return self.__iter__()
-
-    # fourth level uses definitions from lower levels
-    def itervalues(self):
-        for _, v in self.iteritems():
-            yield v
-    def values(self):
-        return [v for _, v in self.iteritems()]
-    def items(self):
-        return list(self.iteritems())
-    def clear(self):
-        for key in self.keys():
-            del self[key]
-    def setdefault(self, key, default):
-        try:
-            return self[key]
-        except KeyError:
-            self[key] = default
-        return default
-    def pop(self, key, *args):
-        if len(args) > 1:
-            raise TypeError, "pop expected at most 2 arguments, got "\
-                              + repr(1 + len(args))
-        try:
-            value = self[key]
-        except KeyError:
-            if args:
-                return args[0]
-            raise
-        del self[key]
-        return value
-    def popitem(self):
-        try:
-            k, v = self.iteritems().next()
-        except StopIteration:
-            raise KeyError, 'container is empty'
-        del self[k]
-        return (k, v)
-    def update(self, other):
-        # Make progressively weaker assumptions about "other"
-        if hasattr(other, 'iteritems'):  # iteritems saves memory and lookups
-            for k, v in other.iteritems():
-                self[k] = v
-        elif hasattr(other, '__iter__'): # iter saves memory
-            for k in other:
-                self[k] = other[k]
-        else:
-            for k in other.keys():
-                self[k] = other[k]
-    def get(self, key, default=None):
-        try:
-            return self[key]
-        except KeyError:
-            return default
-    def __repr__(self):
-        return repr(dict(self.iteritems()))
-    def __cmp__(self, other):
-        if other is None:
-            return 1
-        if isinstance(other, DictMixin):
-            other = dict(other.iteritems())
-        return cmp(dict(self.iteritems()), other)
-    def __len__(self):
-        return len(self.keys())
-    
-    def __nonzero__(self):
-        return bool(self.iteritems())
diff --git a/lib/paste/util/__init__.py b/lib/paste/util/__init__.py
@@ -1,4 +0,0 @@
-"""
-Package for miscellaneous routines that do not depend on other parts
-of Paste
-"""
diff --git a/lib/paste/util/classinit.py b/lib/paste/util/classinit.py
@@ -1,42 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-class ClassInitMeta(type):
-
-    def __new__(meta, class_name, bases, new_attrs):
-        cls = type.__new__(meta, class_name, bases, new_attrs)
-        if (new_attrs.has_key('__classinit__')
-            and not isinstance(cls.__classinit__, staticmethod)):
-            setattr(cls, '__classinit__',
-                    staticmethod(cls.__classinit__.im_func))
-        if hasattr(cls, '__classinit__'):
-            cls.__classinit__(cls, new_attrs)
-        return cls
-
-def build_properties(cls, new_attrs):
-    """
-    Given a class and a new set of attributes (as passed in by
-    __classinit__), create or modify properties based on functions
-    with special names ending in __get, __set, and __del.
-    """
-    for name, value in new_attrs.items():
-        if (name.endswith('__get') or name.endswith('__set')
-            or name.endswith('__del')):
-            base = name[:-5]
-            if hasattr(cls, base):
-                old_prop = getattr(cls, base)
-                if not isinstance(old_prop, property):
-                    raise ValueError(
-                        "Attribute %s is a %s, not a property; function %s is named like a property"
-                        % (base, type(old_prop), name))
-                attrs = {'fget': old_prop.fget,
-                         'fset': old_prop.fset,
-                         'fdel': old_prop.fdel,
-                         'doc': old_prop.__doc__}
-            else:
-                attrs = {}
-            attrs['f' + name[-3:]] = value
-            if name.endswith('__get') and value.__doc__:
-                attrs['doc'] = value.__doc__
-            new_prop = property(**attrs)
-            setattr(cls, base, new_prop)
diff --git a/lib/paste/util/classinstance.py b/lib/paste/util/classinstance.py
@@ -1,38 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-class classinstancemethod(object):
-    """
-    Acts like a class method when called from a class, like an
-    instance method when called by an instance.  The method should
-    take two arguments, 'self' and 'cls'; one of these will be None
-    depending on how the method was called.
-    """
-
-    def __init__(self, func):
-        self.func = func
-        self.__doc__ = func.__doc__
-
-    def __get__(self, obj, type=None):
-        return _methodwrapper(self.func, obj=obj, type=type)
-
-class _methodwrapper(object):
-
-    def __init__(self, func, obj, type):
-        self.func = func
-        self.obj = obj
-        self.type = type
-
-    def __call__(self, *args, **kw):
-        assert not kw.has_key('self') and not kw.has_key('cls'), (
-            "You cannot use 'self' or 'cls' arguments to a "
-            "classinstancemethod")
-        return self.func(*((self.obj, self.type) + args), **kw)
-
-    def __repr__(self):
-        if self.obj is None:
-            return ('<bound class method %s.%s>'
-                    % (self.type.__name__, self.func.func_name))
-        else:
-            return ('<bound method %s.%s of %r>'
-                    % (self.type.__name__, self.func.func_name, self.obj))
diff --git a/lib/paste/util/converters.py b/lib/paste/util/converters.py
@@ -1,26 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-def asbool(obj):
-    if isinstance(obj, (str, unicode)):
-        obj = obj.strip().lower()
-        if obj in ['true', 'yes', 'on', 'y', 't', '1']:
-            return True
-        elif obj in ['false', 'no', 'off', 'n', 'f', '0']:
-            return False
-        else:
-            raise ValueError(
-                "String is not true/false: %r" % obj)
-    return bool(obj)
-
-def aslist(obj, sep=None, strip=True):
-    if isinstance(obj, (str, unicode)):
-        lst = obj.split(sep)
-        if strip:
-            lst = [v.strip() for v in lst]
-        return lst
-    elif isinstance(obj, (list, tuple)):
-        return obj
-    elif obj is None:
-        return []
-    else:
-        return [obj]
diff --git a/lib/paste/util/dateinterval.py b/lib/paste/util/dateinterval.py
@@ -1,103 +0,0 @@
-"""
-DateInterval.py
-
-Convert interval strings (in the form of 1w2d, etc) to
-seconds, and back again.  Is not exactly about months or
-years (leap years in particular).
-
-Accepts (y)ear, (b)month, (w)eek, (d)ay, (h)our, (m)inute, (s)econd.
-
-Exports only timeEncode and timeDecode functions.  
-"""
-
-import re
-
-__all__ = ['interval_decode', 'interval_encode']
-
-second = 1
-minute = second*60
-hour = minute*60
-day = hour*24
-week = day*7
-month = day*30
-year = day*365
-timeValues = {
-    'y': year,
-    'b': month,
-    'w': week,
-    'd': day,
-    'h': hour,
-    'm': minute,
-    's': second,
-    }
-timeOrdered = timeValues.items()
-timeOrdered.sort(lambda a, b: -cmp(a[1], b[1]))
-    
-def interval_encode(seconds, include_sign=False):
-    """Encodes a number of seconds (representing a time interval)
-    into a form like 1h2d3s.
-
-    >>> interval_encode(10)
-    '10s'
-    >>> interval_encode(493939)
-    '5d17h12m19s'
-    """
-    s = ''
-    orig = seconds
-    seconds = abs(seconds)
-    for char, amount in timeOrdered:
-        if seconds >= amount:
-            i, seconds = divmod(seconds, amount)
-            s += '%i%s' % (i, char)
-    if orig < 0:
-        s = '-' + s
-    elif not orig:
-        return '0'
-    elif include_sign:
-        s = '+' + s
-    return s
-
-_timeRE = re.compile(r'[0-9]+[a-zA-Z]')
-def interval_decode(s):
-    """Decodes a number in the format 1h4d3m (1 hour, 3 days, 3 minutes)
-    into a number of seconds
-
-    >>> interval_decode('40s')
-    40
-    >>> interval_decode('10000s')
-    10000
-    >>> interval_decode('3d1w45s')
-    864045
-    """
-    time = 0
-    sign = 1
-    s = s.strip()
-    if s.startswith('-'):
-        s = s[1:]
-        sign = -1
-    elif s.startswith('+'):
-        s = s[1:]
-    for match in allMatches(s, _timeRE):
-        char = match.group(0)[-1].lower()
-        if not timeValues.has_key(char):
-            # @@: should signal error
-            continue
-        time += int(match.group(0)[:-1]) * timeValues[char]
-    return time
-
-# @@-sgd 2002-12-23 - this function does not belong in this module, find a better place.
-def allMatches(source, regex):
-    """Return a list of matches for regex in source
-    """
-    pos = 0
-    end = len(source)
-    rv = []
-    match = regex.search(source, pos)
-    while match:
-        rv.append(match)
-        match = regex.search(source, match.end() )
-    return rv
-
-if __name__ == '__main__':
-    import doctest
-    doctest.testmod()
diff --git a/lib/paste/util/datetimeutil.py b/lib/paste/util/datetimeutil.py
@@ -1,361 +0,0 @@
-# (c) 2005 Clark C. Evans and contributors
-# This module is part of the Python Paste Project and is released under
-# the MIT License: http://www.opensource.org/licenses/mit-license.php
-# Some of this code was funded by: http://prometheusresearch.com
-"""
-Date, Time, and Timespan Parsing Utilities
-
-This module contains parsing support to create "human friendly"
-``datetime`` object parsing.  The explicit goal of these routines is
-to provide a multi-format date/time support not unlike that found in
-Microsoft Excel.  In most approaches, the input is very "strict" to
-prevent errors -- however, this approach is much more liberal since we
-are assuming the user-interface is parroting back the normalized value
-and thus the user has immediate feedback if the data is not typed in
-correctly.
-
-  ``parse_date`` and ``normalize_date``
-
-     These functions take a value like '9 jan 2007' and returns either an
-     ``date`` object, or an ISO 8601 formatted date value such
-     as '2007-01-09'.  There is an option to provide an Oracle database
-     style output as well, ``09 JAN 2007``, but this is not the default.
-
-     This module always treats '/' delimiters as using US date order
-     (since the author's clients are US based), hence '1/9/2007' is
-     January 9th.  Since this module treats the '-' as following
-     European order this supports both modes of data-entry; together
-     with immediate parroting back the result to the screen, the author
-     has found this approach to work well in pratice.
-
-  ``parse_time`` and ``normalize_time``
-
-     These functions take a value like '1 pm' and returns either an
-     ``time`` object, or an ISO 8601 formatted 24h clock time
-     such as '13:00'.  There is an option to provide for US style time
-     values, '1:00 PM', however this is not the default.
-
-  ``parse_datetime`` and ``normalize_datetime``
-
-     These functions take a value like '9 jan 2007 at 1 pm' and returns
-     either an ``datetime`` object, or an ISO 8601 formatted
-     return (without the T) such as '2007-01-09 13:00'. There is an
-     option to provide for Oracle / US style, '09 JAN 2007 @ 1:00 PM',
-     however this is not the default.
-
-  ``parse_delta`` and ``normalize_delta``
-
-     These functions take a value like '1h 15m' and returns either an
-     ``timedelta`` object, or an 2-decimal fixed-point
-     numerical value in hours, such as '1.25'.  The rationale is to
-     support meeting or time-billing lengths, not to be an accurate
-     representation in mili-seconds.  As such not all valid
-     ``timedelta`` values will have a normalized representation.
-
-"""
-from datetime import timedelta, time, date
-from time import localtime
-import string
-
-__all__ = ['parse_timedelta', 'normalize_timedelta',
-           'parse_time', 'normalize_time',
-           'parse_date', 'normalize_date']
-
-def _number(val):
-    try:
-        return string.atoi(val)
-    except:
-        return None
-
-#
-# timedelta
-#
-def parse_timedelta(val):
-    """
-    returns a ``timedelta`` object, or None
-    """
-    if not val:
-        return None
-    val = string.lower(val)
-    if "." in val:
-        val = float(val)
-        return timedelta(hours=int(val), minutes=60*(val % 1.0))
-    fHour = ("h" in val or ":" in val)
-    fMin  = ("m" in val or ":" in val)
-    fFraction = "." in val
-    for noise in "minu:teshour()":
-        val = string.replace(val, noise, ' ')
-    val = string.strip(val)
-    val = string.split(val)
-    hr = 0.0
-    mi = 0
-    val.reverse()
-    if fHour:
-        hr = int(val.pop())
-    if fMin:
-        mi = int(val.pop())
-    if len(val) > 0 and not hr:
-        hr = int(val.pop())
-    return timedelta(hours=hr, minutes=mi)
-
-def normalize_timedelta(val):
-    """
-    produces a normalized string value of the timedelta
-
-    This module returns a normalized time span value consisting of the
-    number of hours in fractional form. For example '1h 15min' is
-    formatted as 01.25.
-    """
-    if type(val) == str:
-        val = parse_timedelta(val)
-    if not val:
-        return ''
-    hr = val.seconds/3600
-    mn = (val.seconds % 3600)/60
-    return "%d.%02d" % (hr, mn * 100/60)
-
-#
-# time
-#
-def parse_time(val):
-    if not val:
-        return None
-    hr = mi = 0
-    val = string.lower(val)
-    amflag = (-1 != string.find(val, 'a'))  # set if AM is found
-    pmflag = (-1 != string.find(val, 'p'))  # set if PM is found
-    for noise in ":amp.":
-        val = string.replace(val, noise, ' ')
-    val = string.split(val)
-    if len(val) > 1:
-        hr = int(val[0])
-        mi = int(val[1])
-    else:
-        val = val[0]
-        if len(val) < 1:
-            pass
-        elif 'now' == val:
-            tm = localtime()
-            hr = tm[3]
-            mi = tm[4]
-        elif 'noon' == val:
-            hr = 12
-        elif len(val) < 3:
-            hr = int(val)
-            if not amflag and not pmflag and hr < 7:
-                hr += 12
-        elif len(val) < 5:
-            hr = int(val[:-2])
-            mi = int(val[-2:])
-        else:
-            hr = int(val[:1])
-    if amflag and hr >= 12:
-        hr = hr - 12
-    if pmflag and hr < 12:
-        hr = hr + 12
-    return time(hr, mi)
-
-def normalize_time(value, ampm):
-    if not value:
-        return ''
-    if type(value) == str:
-        value = parse_time(value)
-    if not ampm:
-        return "%02d:%02d" % (value.hour, value.minute)
-    hr = value.hour
-    am = "AM"
-    if hr < 1 or hr > 23:
-        hr = 12
-    elif hr >= 12:
-        am = "PM"
-        if hr > 12:
-            hr = hr - 12
-    return "%02d:%02d %s" % (hr, value.minute, am)
-
-#
-# Date Processing
-#
-
-_one_day = timedelta(days=1)
-
-_str2num = {'jan':1, 'feb':2, 'mar':3, 'apr':4,  'may':5, 'jun':6,
-            'jul':7, 'aug':8, 'sep':9, 'oct':10, 'nov':11, 'dec':12 }
-
-def _month(val):
-    for (key, mon) in _str2num.items():
-        if key in val:
-            return mon
-    raise TypeError("unknown month '%s'" % val)
-
-_days_in_month = {1: 31, 2: 28, 3: 31, 4: 30, 5: 31, 6: 30,
-                  7: 31, 8: 31, 9: 30, 10: 31, 11: 30, 12: 31,
-                  }
-_num2str = {1: 'Jan', 2: 'Feb', 3: 'Mar', 4: 'Apr', 5: 'May', 6: 'Jun',
-            7: 'Jul', 8: 'Aug', 9: 'Sep', 10: 'Oct', 11: 'Nov', 12: 'Dec',
-            }
-_wkdy = ("mon", "tue", "wed", "thu", "fri", "sat", "sun")
-
-def parse_date(val):
-    if not(val):
-        return None
-    val = string.lower(val)
-    now = None
-
-    # optimized check for YYYY-MM-DD
-    strict = val.split("-")
-    if len(strict) == 3:
-        (y, m, d) = strict
-        if "+" in d:
-            d = d.split("+")[0]
-        if " " in d:
-            d = d.split(" ")[0]
-        try:
-            now = date(int(y), int(m), int(d))
-            val = "xxx" + val[10:]
-        except ValueError:
-            pass
-
-    # allow for 'now', 'mon', 'tue', etc.
-    if not now:
-        chk = val[:3]
-        if chk in ('now','tod'):
-            now = date.today()
-        elif chk in _wkdy:
-            now = date.today()
-            idx = list(_wkdy).index(chk) + 1
-            while now.isoweekday() != idx:
-                now += _one_day
-
-    # allow dates to be modified via + or - /w number of days, so
-    # that now+3 is three days from now
-    if now:
-        tail = val[3:].strip()
-        tail = tail.replace("+"," +").replace("-"," -")
-        for item in tail.split():
-            try:
-                days = int(item)
-            except ValueError:
-                pass
-            else:
-                now += timedelta(days=days)
-        return now
-
-    # ok, standard parsing
-    yr = mo = dy = None
-    for noise in ('/', '-', ',', '*'):
-        val = string.replace(val, noise, ' ')
-    for noise in _wkdy:
-        val = string.replace(val, noise, ' ')
-    out = []
-    last = False
-    ldig = False
-    for ch in val:
-        if ch.isdigit():
-            if last and not ldig:
-               out.append(' ')
-            last = ldig = True
-        else:
-            if ldig:
-                out.append(' ')
-                ldig = False
-            last = True
-        out.append(ch)
-    val = string.split("".join(out))
-    if 3 == len(val):
-        a = _number(val[0])
-        b = _number(val[1])
-        c = _number(val[2])
-        if len(val[0]) == 4:
-            yr = a
-            if b:  # 1999 6 23
-                mo = b
-                dy = c
-            else:  # 1999 Jun 23
-                mo = _month(val[1])
-                dy = c
-        elif a > 0:
-            yr = c
-            if len(val[2]) < 4:
-                raise TypeError("four digit year required")
-            if b: # 6 23 1999
-                dy = b
-                mo = a
-            else: # 23 Jun 1999
-                dy = a
-                mo = _month(val[1])
-        else: # Jun 23, 2000
-            dy = b
-            yr = c
-            if len(val[2]) < 4:
-                raise TypeError("four digit year required")
-            mo = _month(val[0])
-    elif 2 == len(val):
-        a = _number(val[0])
-        b = _number(val[1])
-        if a > 999:
-            yr = a
-            dy = 1
-            if b > 0: # 1999 6
-                mo = b
-            else: # 1999 Jun
-                mo = _month(val[1])
-        elif a > 0:
-            if b > 999: # 6 1999
-                mo = a
-                yr = b
-                dy = 1
-            elif b > 0: # 6 23
-                mo = a
-                dy = b
-            else: # 23 Jun
-                dy = a
-                mo = _month(val[1])
-        else:
-            if b > 999: # Jun 2001
-                yr = b
-                dy = 1
-            else:  # Jun 23
-                dy = b
-            mo = _month(val[0])
-    elif 1 == len(val):
-        val = val[0]
-        if not val.isdigit():
-            mo = _month(val)
-            if mo is not None:
-                dy = 1
-        else:
-            v = _number(val)
-            val = str(v)
-            if 8 == len(val): # 20010623
-                yr = _number(val[:4])
-                mo = _number(val[4:6])
-                dy = _number(val[6:])
-            elif len(val) in (3,4):
-                if v > 1300: # 2004
-                    yr = v
-                    mo = 1
-                    dy = 1
-                else:        # 1202
-                    mo = _number(val[:-2])
-                    dy = _number(val[-2:])
-            elif v < 32:
-                dy = v
-            else:
-                raise TypeError("four digit year required")
-    tm = localtime()
-    if mo is None:
-        mo = tm[1]
-    if dy is None:
-        dy = tm[2]
-    if yr is None:
-        yr = tm[0]
-    return date(yr, mo, dy)
-
-def normalize_date(val, iso8601=True):
-    if not val:
-        return ''
-    if type(val) == str:
-        val = parse_date(val)
-    if iso8601:
-        return "%4d-%02d-%02d" % (val.year, val.month, val.day)
-    return "%02d %s %4d" % (val.day, _num2str[val.month], val.year)
diff --git a/lib/paste/util/doctest24.py b/lib/paste/util/doctest24.py
@@ -1,2665 +0,0 @@
-# Module doctest.
-# Released to the public domain 16-Jan-2001, by Tim Peters (tim@python.org).
-# Major enhancements and refactoring by:
-#     Jim Fulton
-#     Edward Loper
-
-# Provided as-is; use at your own risk; no warranty; no promises; enjoy!
-
-r"""Module doctest -- a framework for running examples in docstrings.
-
-In simplest use, end each module M to be tested with:
-
-def _test():
-    import doctest
-    doctest.testmod()
-
-if __name__ == "__main__":
-    _test()
-
-Then running the module as a script will cause the examples in the
-docstrings to get executed and verified:
-
-python M.py
-
-This won't display anything unless an example fails, in which case the
-failing example(s) and the cause(s) of the failure(s) are printed to stdout
-(why not stderr? because stderr is a lame hack <0.2 wink>), and the final
-line of output is "Test failed.".
-
-Run it with the -v switch instead:
-
-python M.py -v
-
-and a detailed report of all examples tried is printed to stdout, along
-with assorted summaries at the end.
-
-You can force verbose mode by passing "verbose=True" to testmod, or prohibit
-it by passing "verbose=False".  In either of those cases, sys.argv is not
-examined by testmod.
-
-There are a variety of other ways to run doctests, including integration
-with the unittest framework, and support for running non-Python text
-files containing doctests.  There are also many ways to override parts
-of doctest's default behaviors.  See the Library Reference Manual for
-details.
-"""
-
-__docformat__ = 'reStructuredText en'
-
-__all__ = [
-    # 0, Option Flags
-    'register_optionflag',
-    'DONT_ACCEPT_TRUE_FOR_1',
-    'DONT_ACCEPT_BLANKLINE',
-    'NORMALIZE_WHITESPACE',
-    'ELLIPSIS',
-    'IGNORE_EXCEPTION_DETAIL',
-    'COMPARISON_FLAGS',
-    'REPORT_UDIFF',
-    'REPORT_CDIFF',
-    'REPORT_NDIFF',
-    'REPORT_ONLY_FIRST_FAILURE',
-    'REPORTING_FLAGS',
-    # 1. Utility Functions
-    'is_private',
-    # 2. Example & DocTest
-    'Example',
-    'DocTest',
-    # 3. Doctest Parser
-    'DocTestParser',
-    # 4. Doctest Finder
-    'DocTestFinder',
-    # 5. Doctest Runner
-    'DocTestRunner',
-    'OutputChecker',
-    'DocTestFailure',
-    'UnexpectedException',
-    'DebugRunner',
-    # 6. Test Functions
-    'testmod',
-    'testfile',
-    'run_docstring_examples',
-    # 7. Tester
-    'Tester',
-    # 8. Unittest Support
-    'DocTestSuite',
-    'DocFileSuite',
-    'set_unittest_reportflags',
-    # 9. Debugging Support
-    'script_from_examples',
-    'testsource',
-    'debug_src',
-    'debug',
-]
-
-import __future__
-
-import sys, traceback, inspect, linecache, os, re, types
-import unittest, difflib, pdb, tempfile
-import warnings
-from StringIO import StringIO
-
-# Don't whine about the deprecated is_private function in this
-# module's tests.
-warnings.filterwarnings("ignore", "is_private", DeprecationWarning,
-                        __name__, 0)
-
-# There are 4 basic classes:
-#  - Example: a <source, want> pair, plus an intra-docstring line number.
-#  - DocTest: a collection of examples, parsed from a docstring, plus
-#    info about where the docstring came from (name, filename, lineno).
-#  - DocTestFinder: extracts DocTests from a given object's docstring and
-#    its contained objects' docstrings.
-#  - DocTestRunner: runs DocTest cases, and accumulates statistics.
-#
-# So the basic picture is:
-#
-#                             list of:
-# +------+                   +---------+                   +-------+
-# |object| --DocTestFinder-> | DocTest | --DocTestRunner-> |results|
-# +------+                   +---------+                   +-------+
-#                            | Example |
-#                            |   ...   |
-#                            | Example |
-#                            +---------+
-
-# Option constants.
-
-OPTIONFLAGS_BY_NAME = {}
-def register_optionflag(name):
-    flag = 1 << len(OPTIONFLAGS_BY_NAME)
-    OPTIONFLAGS_BY_NAME[name] = flag
-    return flag
-
-DONT_ACCEPT_TRUE_FOR_1 = register_optionflag('DONT_ACCEPT_TRUE_FOR_1')
-DONT_ACCEPT_BLANKLINE = register_optionflag('DONT_ACCEPT_BLANKLINE')
-NORMALIZE_WHITESPACE = register_optionflag('NORMALIZE_WHITESPACE')
-ELLIPSIS = register_optionflag('ELLIPSIS')
-IGNORE_EXCEPTION_DETAIL = register_optionflag('IGNORE_EXCEPTION_DETAIL')
-
-COMPARISON_FLAGS = (DONT_ACCEPT_TRUE_FOR_1 |
-                    DONT_ACCEPT_BLANKLINE |
-                    NORMALIZE_WHITESPACE |
-                    ELLIPSIS |
-                    IGNORE_EXCEPTION_DETAIL)
-
-REPORT_UDIFF = register_optionflag('REPORT_UDIFF')
-REPORT_CDIFF = register_optionflag('REPORT_CDIFF')
-REPORT_NDIFF = register_optionflag('REPORT_NDIFF')
-REPORT_ONLY_FIRST_FAILURE = register_optionflag('REPORT_ONLY_FIRST_FAILURE')
-
-REPORTING_FLAGS = (REPORT_UDIFF |
-                   REPORT_CDIFF |
-                   REPORT_NDIFF |
-                   REPORT_ONLY_FIRST_FAILURE)
-
-# Special string markers for use in `want` strings:
-BLANKLINE_MARKER = '<BLANKLINE>'
-ELLIPSIS_MARKER = '...'
-
-######################################################################
-## Table of Contents
-######################################################################
-#  1. Utility Functions
-#  2. Example & DocTest -- store test cases
-#  3. DocTest Parser -- extracts examples from strings
-#  4. DocTest Finder -- extracts test cases from objects
-#  5. DocTest Runner -- runs test cases
-#  6. Test Functions -- convenient wrappers for testing
-#  7. Tester Class -- for backwards compatibility
-#  8. Unittest Support
-#  9. Debugging Support
-# 10. Example Usage
-
-######################################################################
-## 1. Utility Functions
-######################################################################
-
-def is_private(prefix, base):
-    """prefix, base -> true iff name prefix + "." + base is "private".
-
-    Prefix may be an empty string, and base does not contain a period.
-    Prefix is ignored (although functions you write conforming to this
-    protocol may make use of it).
-    Return true iff base begins with an (at least one) underscore, but
-    does not both begin and end with (at least) two underscores.
-
-    >>> is_private("a.b", "my_func")
-    False
-    >>> is_private("____", "_my_func")
-    True
-    >>> is_private("someclass", "__init__")
-    False
-    >>> is_private("sometypo", "__init_")
-    True
-    >>> is_private("x.y.z", "_")
-    True
-    >>> is_private("_x.y.z", "__")
-    False
-    >>> is_private("", "")  # senseless but consistent
-    False
-    """
-    warnings.warn("is_private is deprecated; it wasn't useful; "
-                  "examine DocTestFinder.find() lists instead",
-                  DeprecationWarning, stacklevel=2)
-    return base[:1] == "_" and not base[:2] == "__" == base[-2:]
-
-def _extract_future_flags(globs):
-    """
-    Return the compiler-flags associated with the future features that
-    have been imported into the given namespace (globs).
-    """
-    flags = 0
-    for fname in __future__.all_feature_names:
-        feature = globs.get(fname, None)
-        if feature is getattr(__future__, fname):
-            flags |= feature.compiler_flag
-    return flags
-
-def _normalize_module(module, depth=2):
-    """
-    Return the module specified by `module`.  In particular:
-      - If `module` is a module, then return module.
-      - If `module` is a string, then import and return the
-        module with that name.
-      - If `module` is None, then return the calling module.
-        The calling module is assumed to be the module of
-        the stack frame at the given depth in the call stack.
-    """
-    if inspect.ismodule(module):
-        return module
-    elif isinstance(module, (str, unicode)):
-        return __import__(module, globals(), locals(), ["*"])
-    elif module is None:
-        return sys.modules[sys._getframe(depth).f_globals['__name__']]
-    else:
-        raise TypeError("Expected a module, string, or None")
-
-def _indent(s, indent=4):
-    """
-    Add the given number of space characters to the beginning every
-    non-blank line in `s`, and return the result.
-    """
-    # This regexp matches the start of non-blank lines:
-    return re.sub('(?m)^(?!$)', indent*' ', s)
-
-def _exception_traceback(exc_info):
-    """
-    Return a string containing a traceback message for the given
-    exc_info tuple (as returned by sys.exc_info()).
-    """
-    # Get a traceback message.
-    excout = StringIO()
-    exc_type, exc_val, exc_tb = exc_info
-    traceback.print_exception(exc_type, exc_val, exc_tb, file=excout)
-    return excout.getvalue()
-
-# Override some StringIO methods.
-class _SpoofOut(StringIO):
-    def getvalue(self):
-        result = StringIO.getvalue(self)
-        # If anything at all was written, make sure there's a trailing
-        # newline.  There's no way for the expected output to indicate
-        # that a trailing newline is missing.
-        if result and not result.endswith("\n"):
-            result += "\n"
-        # Prevent softspace from screwing up the next test case, in
-        # case they used print with a trailing comma in an example.
-        if hasattr(self, "softspace"):
-            del self.softspace
-        return result
-
-    def truncate(self,   size=None):
-        StringIO.truncate(self, size)
-        if hasattr(self, "softspace"):
-            del self.softspace
-
-# Worst-case linear-time ellipsis matching.
-def _ellipsis_match(want, got):
-    """
-    Essentially the only subtle case:
-    >>> _ellipsis_match('aa...aa', 'aaa')
-    False
-    """
-    if ELLIPSIS_MARKER not in want:
-        return want == got
-
-    # Find "the real" strings.
-    ws = want.split(ELLIPSIS_MARKER)
-    assert len(ws) >= 2
-
-    # Deal with exact matches possibly needed at one or both ends.
-    startpos, endpos = 0, len(got)
-    w = ws[0]
-    if w:   # starts with exact match
-        if got.startswith(w):
-            startpos = len(w)
-            del ws[0]
-        else:
-            return False
-    w = ws[-1]
-    if w:   # ends with exact match
-        if got.endswith(w):
-            endpos -= len(w)
-            del ws[-1]
-        else:
-            return False
-
-    if startpos > endpos:
-        # Exact end matches required more characters than we have, as in
-        # _ellipsis_match('aa...aa', 'aaa')
-        return False
-
-    # For the rest, we only need to find the leftmost non-overlapping
-    # match for each piece.  If there's no overall match that way alone,
-    # there's no overall match period.
-    for w in ws:
-        # w may be '' at times, if there are consecutive ellipses, or
-        # due to an ellipsis at the start or end of `want`.  That's OK.
-        # Search for an empty string succeeds, and doesn't change startpos.
-        startpos = got.find(w, startpos, endpos)
-        if startpos < 0:
-            return False
-        startpos += len(w)
-
-    return True
-
-def _comment_line(line):
-    "Return a commented form of the given line"
-    line = line.rstrip()
-    if line:
-        return '# '+line
-    else:
-        return '#'
-
-class _OutputRedirectingPdb(pdb.Pdb):
-    """
-    A specialized version of the python debugger that redirects stdout
-    to a given stream when interacting with the user.  Stdout is *not*
-    redirected when traced code is executed.
-    """
-    def __init__(self, out):
-        self.__out = out
-        pdb.Pdb.__init__(self)
-
-    def trace_dispatch(self, *args):
-        # Redirect stdout to the given stream.
-        save_stdout = sys.stdout
-        sys.stdout = self.__out
-        # Call Pdb's trace dispatch method.
-        try:
-            return pdb.Pdb.trace_dispatch(self, *args)
-        finally:
-            sys.stdout = save_stdout
-
-# [XX] Normalize with respect to os.path.pardir?
-def _module_relative_path(module, path):
-    if not inspect.ismodule(module):
-        raise TypeError, 'Expected a module: %r' % module
-    if path.startswith('/'):
-        raise ValueError, 'Module-relative files may not have absolute paths'
-
-    # Find the base directory for the path.
-    if hasattr(module, '__file__'):
-        # A normal module/package
-        basedir = os.path.split(module.__file__)[0]
-    elif module.__name__ == '__main__':
-        # An interactive session.
-        if len(sys.argv)>0 and sys.argv[0] != '':
-            basedir = os.path.split(sys.argv[0])[0]
-        else:
-            basedir = os.curdir
-    else:
-        # A module w/o __file__ (this includes builtins)
-        raise ValueError("Can't resolve paths relative to the module " +
-                         module + " (it has no __file__)")
-
-    # Combine the base directory and the path.
-    return os.path.join(basedir, *(path.split('/')))
-
-######################################################################
-## 2. Example & DocTest
-######################################################################
-## - An "example" is a <source, want> pair, where "source" is a
-##   fragment of source code, and "want" is the expected output for
-##   "source."  The Example class also includes information about
-##   where the example was extracted from.
-##
-## - A "doctest" is a collection of examples, typically extracted from
-##   a string (such as an object's docstring).  The DocTest class also
-##   includes information about where the string was extracted from.
-
-class Example:
-    """
-    A single doctest example, consisting of source code and expected
-    output.  `Example` defines the following attributes:
-
-      - source: A single Python statement, always ending with a newline.
-        The constructor adds a newline if needed.
-
-      - want: The expected output from running the source code (either
-        from stdout, or a traceback in case of exception).  `want` ends
-        with a newline unless it's empty, in which case it's an empty
-        string.  The constructor adds a newline if needed.
-
-      - exc_msg: The exception message generated by the example, if
-        the example is expected to generate an exception; or `None` if
-        it is not expected to generate an exception.  This exception
-        message is compared against the return value of
-        `traceback.format_exception_only()`.  `exc_msg` ends with a
-        newline unless it's `None`.  The constructor adds a newline
-        if needed.
-
-      - lineno: The line number within the DocTest string containing
-        this Example where the Example begins.  This line number is
-        zero-based, with respect to the beginning of the DocTest.
-
-      - indent: The example's indentation in the DocTest string.
-        I.e., the number of space characters that preceed the
-        example's first prompt.
-
-      - options: A dictionary mapping from option flags to True or
-        False, which is used to override default options for this
-        example.  Any option flags not contained in this dictionary
-        are left at their default value (as specified by the
-        DocTestRunner's optionflags).  By default, no options are set.
-    """
-    def __init__(self, source, want, exc_msg=None, lineno=0, indent=0,
-                 options=None):
-        # Normalize inputs.
-        if not source.endswith('\n'):
-            source += '\n'
-        if want and not want.endswith('\n'):
-            want += '\n'
-        if exc_msg is not None and not exc_msg.endswith('\n'):
-            exc_msg += '\n'
-        # Store properties.
-        self.source = source
-        self.want = want
-        self.lineno = lineno
-        self.indent = indent
-        if options is None: options = {}
-        self.options = options
-        self.exc_msg = exc_msg
-
-class DocTest:
-    """
-    A collection of doctest examples that should be run in a single
-    namespace.  Each `DocTest` defines the following attributes:
-
-      - examples: the list of examples.
-
-      - globs: The namespace (aka globals) that the examples should
-        be run in.
-
-      - name: A name identifying the DocTest (typically, the name of
-        the object whose docstring this DocTest was extracted from).
-
-      - filename: The name of the file that this DocTest was extracted
-        from, or `None` if the filename is unknown.
-
-      - lineno: The line number within filename where this DocTest
-        begins, or `None` if the line number is unavailable.  This
-        line number is zero-based, with respect to the beginning of
-        the file.
-
-      - docstring: The string that the examples were extracted from,
-        or `None` if the string is unavailable.
-    """
-    def __init__(self, examples, globs, name, filename, lineno, docstring):
-        """
-        Create a new DocTest containing the given examples.  The
-        DocTest's globals are initialized with a copy of `globs`.
-        """
-        assert not isinstance(examples, basestring), \
-               "DocTest no longer accepts str; use DocTestParser instead"
-        self.examples = examples
-        self.docstring = docstring
-        self.globs = globs.copy()
-        self.name = name
-        self.filename = filename
-        self.lineno = lineno
-
-    def __repr__(self):
-        if len(self.examples) == 0:
-            examples = 'no examples'
-        elif len(self.examples) == 1:
-            examples = '1 example'
-        else:
-            examples = '%d examples' % len(self.examples)
-        return ('<DocTest %s from %s:%s (%s)>' %
-                (self.name, self.filename, self.lineno, examples))
-
-
-    # This lets us sort tests by name:
-    def __cmp__(self, other):
-        if not isinstance(other, DocTest):
-            return -1
-        return cmp((self.name, self.filename, self.lineno, id(self)),
-                   (other.name, other.filename, other.lineno, id(other)))
-
-######################################################################
-## 3. DocTestParser
-######################################################################
-
-class DocTestParser:
-    """
-    A class used to parse strings containing doctest examples.
-    """
-    # This regular expression is used to find doctest examples in a
-    # string.  It defines three groups: `source` is the source code
-    # (including leading indentation and prompts); `indent` is the
-    # indentation of the first (PS1) line of the source code; and
-    # `want` is the expected output (including leading indentation).
-    _EXAMPLE_RE = re.compile(r'''
-        # Source consists of a PS1 line followed by zero or more PS2 lines.
-        (?P<source>
-            (?:^(?P<indent> [ ]*) >>>    .*)    # PS1 line
-            (?:\n           [ ]*  \.\.\. .*)*)  # PS2 lines
-        \n?
-        # Want consists of any non-blank lines that do not start with PS1.
-        (?P<want> (?:(?![ ]*$)    # Not a blank line
-                     (?![ ]*>>>)  # Not a line starting with PS1
-                     .*$\n?       # But any other line
-                  )*)
-        ''', re.MULTILINE | re.VERBOSE)
-
-    # A regular expression for handling `want` strings that contain
-    # expected exceptions.  It divides `want` into three pieces:
-    #    - the traceback header line (`hdr`)
-    #    - the traceback stack (`stack`)
-    #    - the exception message (`msg`), as generated by
-    #      traceback.format_exception_only()
-    # `msg` may have multiple lines.  We assume/require that the
-    # exception message is the first non-indented line starting with a word
-    # character following the traceback header line.
-    _EXCEPTION_RE = re.compile(r"""
-        # Grab the traceback header.  Different versions of Python have
-        # said different things on the first traceback line.
-        ^(?P<hdr> Traceback\ \(
-            (?: most\ recent\ call\ last
-            |   innermost\ last
-            ) \) :
-        )
-        \s* $                # toss trailing whitespace on the header.
-        (?P<stack> .*?)      # don't blink: absorb stuff until...
-        ^ (?P<msg> \w+ .*)   #     a line *starts* with alphanum.
-        """, re.VERBOSE | re.MULTILINE | re.DOTALL)
-
-    # A callable returning a true value iff its argument is a blank line
-    # or contains a single comment.
-    _IS_BLANK_OR_COMMENT = re.compile(r'^[ ]*(#.*)?$').match
-
-    def parse(self, string, name='<string>'):
-        """
-        Divide the given string into examples and intervening text,
-        and return them as a list of alternating Examples and strings.
-        Line numbers for the Examples are 0-based.  The optional
-        argument `name` is a name identifying this string, and is only
-        used for error messages.
-        """
-        string = string.expandtabs()
-        # If all lines begin with the same indentation, then strip it.
-        min_indent = self._min_indent(string)
-        if min_indent > 0:
-            string = '\n'.join([l[min_indent:] for l in string.split('\n')])
-
-        output = []
-        charno, lineno = 0, 0
-        # Find all doctest examples in the string:
-        for m in self._EXAMPLE_RE.finditer(string):
-            # Add the pre-example text to `output`.
-            output.append(string[charno:m.start()])
-            # Update lineno (lines before this example)
-            lineno += string.count('\n', charno, m.start())
-            # Extract info from the regexp match.
-            (source, options, want, exc_msg) = \
-                     self._parse_example(m, name, lineno)
-            # Create an Example, and add it to the list.
-            if not self._IS_BLANK_OR_COMMENT(source):
-                output.append( Example(source, want, exc_msg,
-                                    lineno=lineno,
-                                    indent=min_indent+len(m.group('indent')),
-                                    options=options) )
-            # Update lineno (lines inside this example)
-            lineno += string.count('\n', m.start(), m.end())
-            # Update charno.
-            charno = m.end()
-        # Add any remaining post-example text to `output`.
-        output.append(string[charno:])
-        return output
-
-    def get_doctest(self, string, globs, name, filename, lineno):
-        """
-        Extract all doctest examples from the given string, and
-        collect them into a `DocTest` object.
-
-        `globs`, `name`, `filename`, and `lineno` are attributes for
-        the new `DocTest` object.  See the documentation for `DocTest`
-        for more information.
-        """
-        return DocTest(self.get_examples(string, name), globs,
-                       name, filename, lineno, string)
-
-    def get_examples(self, string, name='<string>'):
-        """
-        Extract all doctest examples from the given string, and return
-        them as a list of `Example` objects.  Line numbers are
-        0-based, because it's most common in doctests that nothing
-        interesting appears on the same line as opening triple-quote,
-        and so the first interesting line is called \"line 1\" then.
-
-        The optional argument `name` is a name identifying this
-        string, and is only used for error messages.
-        """
-        return [x for x in self.parse(string, name)
-                if isinstance(x, Example)]
-
-    def _parse_example(self, m, name, lineno):
-        """
-        Given a regular expression match from `_EXAMPLE_RE` (`m`),
-        return a pair `(source, want)`, where `source` is the matched
-        example's source code (with prompts and indentation stripped);
-        and `want` is the example's expected output (with indentation
-        stripped).
-
-        `name` is the string's name, and `lineno` is the line number
-        where the example starts; both are used for error messages.
-        """
-        # Get the example's indentation level.
-        indent = len(m.group('indent'))
-
-        # Divide source into lines; check that they're properly
-        # indented; and then strip their indentation & prompts.
-        source_lines = m.group('source').split('\n')
-        self._check_prompt_blank(source_lines, indent, name, lineno)
-        self._check_prefix(source_lines[1:], ' '*indent + '.', name, lineno)
-        source = '\n'.join([sl[indent+4:] for sl in source_lines])
-
-        # Divide want into lines; check that it's properly indented; and
-        # then strip the indentation.  Spaces before the last newline should
-        # be preserved, so plain rstrip() isn't good enough.
-        want = m.group('want')
-        want_lines = want.split('\n')
-        if len(want_lines) > 1 and re.match(r' *$', want_lines[-1]):
-            del want_lines[-1]  # forget final newline & spaces after it
-        self._check_prefix(want_lines, ' '*indent, name,
-                           lineno + len(source_lines))
-        want = '\n'.join([wl[indent:] for wl in want_lines])
-
-        # If `want` contains a traceback message, then extract it.
-        m = self._EXCEPTION_RE.match(want)
-        if m:
-            exc_msg = m.group('msg')
-        else:
-            exc_msg = None
-
-        # Extract options from the source.
-        options = self._find_options(source, name, lineno)
-
-        return source, options, want, exc_msg
-
-    # This regular expression looks for option directives in the
-    # source code of an example.  Option directives are comments
-    # starting with "doctest:".  Warning: this may give false
-    # positives for string-literals that contain the string
-    # "#doctest:".  Eliminating these false positives would require
-    # actually parsing the string; but we limit them by ignoring any
-    # line containing "#doctest:" that is *followed* by a quote mark.
-    _OPTION_DIRECTIVE_RE = re.compile(r'#\s*doctest:\s*([^\n\'"]*)$',
-                                      re.MULTILINE)
-
-    def _find_options(self, source, name, lineno):
-        """
-        Return a dictionary containing option overrides extracted from
-        option directives in the given source string.
-
-        `name` is the string's name, and `lineno` is the line number
-        where the example starts; both are used for error messages.
-        """
-        options = {}
-        # (note: with the current regexp, this will match at most once:)
-        for m in self._OPTION_DIRECTIVE_RE.finditer(source):
-            option_strings = m.group(1).replace(',', ' ').split()
-            for option in option_strings:
-                if (option[0] not in '+-' or
-                    option[1:] not in OPTIONFLAGS_BY_NAME):
-                    raise ValueError('line %r of the doctest for %s '
-                                     'has an invalid option: %r' %
-                                     (lineno+1, name, option))
-                flag = OPTIONFLAGS_BY_NAME[option[1:]]
-                options[flag] = (option[0] == '+')
-        if options and self._IS_BLANK_OR_COMMENT(source):
-            raise ValueError('line %r of the doctest for %s has an option '
-                             'directive on a line with no example: %r' %
-                             (lineno, name, source))
-        return options
-
-    # This regular expression finds the indentation of every non-blank
-    # line in a string.
-    _INDENT_RE = re.compile('^([ ]*)(?=\S)', re.MULTILINE)
-
-    def _min_indent(self, s):
-        "Return the minimum indentation of any non-blank line in `s`"
-        indents = [len(indent) for indent in self._INDENT_RE.findall(s)]
-        if len(indents) > 0:
-            return min(indents)
-        else:
-            return 0
-
-    def _check_prompt_blank(self, lines, indent, name, lineno):
-        """
-        Given the lines of a source string (including prompts and
-        leading indentation), check to make sure that every prompt is
-        followed by a space character.  If any line is not followed by
-        a space character, then raise ValueError.
-        """
-        for i, line in enumerate(lines):
-            if len(line) >= indent+4 and line[indent+3] != ' ':
-                raise ValueError('line %r of the docstring for %s '
-                                 'lacks blank after %s: %r' %
-                                 (lineno+i+1, name,
-                                  line[indent:indent+3], line))
-
-    def _check_prefix(self, lines, prefix, name, lineno):
-        """
-        Check that every line in the given list starts with the given
-        prefix; if any line does not, then raise a ValueError.
-        """
-        for i, line in enumerate(lines):
-            if line and not line.startswith(prefix):
-                raise ValueError('line %r of the docstring for %s has '
-                                 'inconsistent leading whitespace: %r' %
-                                 (lineno+i+1, name, line))
-
-
-######################################################################
-## 4. DocTest Finder
-######################################################################
-
-class DocTestFinder:
-    """
-    A class used to extract the DocTests that are relevant to a given
-    object, from its docstring and the docstrings of its contained
-    objects.  Doctests can currently be extracted from the following
-    object types: modules, functions, classes, methods, staticmethods,
-    classmethods, and properties.
-    """
-
-    def __init__(self, verbose=False, parser=DocTestParser(),
-                 recurse=True, _namefilter=None, exclude_empty=True):
-        """
-        Create a new doctest finder.
-
-        The optional argument `parser` specifies a class or
-        function that should be used to create new DocTest objects (or
-        objects that implement the same interface as DocTest).  The
-        signature for this factory function should match the signature
-        of the DocTest constructor.
-
-        If the optional argument `recurse` is false, then `find` will
-        only examine the given object, and not any contained objects.
-
-        If the optional argument `exclude_empty` is false, then `find`
-        will include tests for objects with empty docstrings.
-        """
-        self._parser = parser
-        self._verbose = verbose
-        self._recurse = recurse
-        self._exclude_empty = exclude_empty
-        # _namefilter is undocumented, and exists only for temporary backward-
-        # compatibility support of testmod's deprecated isprivate mess.
-        self._namefilter = _namefilter
-
-    def find(self, obj, name=None, module=None, globs=None,
-             extraglobs=None):
-        """
-        Return a list of the DocTests that are defined by the given
-        object's docstring, or by any of its contained objects'
-        docstrings.
-
-        The optional parameter `module` is the module that contains
-        the given object.  If the module is not specified or is None, then
-        the test finder will attempt to automatically determine the
-        correct module.  The object's module is used:
-
-            - As a default namespace, if `globs` is not specified.
-            - To prevent the DocTestFinder from extracting DocTests
-              from objects that are imported from other modules.
-            - To find the name of the file containing the object.
-            - To help find the line number of the object within its
-              file.
-
-        Contained objects whose module does not match `module` are ignored.
-
-        If `module` is False, no attempt to find the module will be made.
-        This is obscure, of use mostly in tests:  if `module` is False, or
-        is None but cannot be found automatically, then all objects are
-        considered to belong to the (non-existent) module, so all contained
-        objects will (recursively) be searched for doctests.
-
-        The globals for each DocTest is formed by combining `globs`
-        and `extraglobs` (bindings in `extraglobs` override bindings
-        in `globs`).  A new copy of the globals dictionary is created
-        for each DocTest.  If `globs` is not specified, then it
-        defaults to the module's `__dict__`, if specified, or {}
-        otherwise.  If `extraglobs` is not specified, then it defaults
-        to {}.
-
-        """
-        # If name was not specified, then extract it from the object.
-        if name is None:
-            name = getattr(obj, '__name__', None)
-            if name is None:
-                raise ValueError("DocTestFinder.find: name must be given "
-                        "when obj.__name__ doesn't exist: %r" %
-                                 (type(obj),))
-
-        # Find the module that contains the given object (if obj is
-        # a module, then module=obj.).  Note: this may fail, in which
-        # case module will be None.
-        if module is False:
-            module = None
-        elif module is None:
-            module = inspect.getmodule(obj)
-
-        # Read the module's source code.  This is used by
-        # DocTestFinder._find_lineno to find the line number for a
-        # given object's docstring.
-        try:
-            file = inspect.getsourcefile(obj) or inspect.getfile(obj)
-            source_lines = linecache.getlines(file)
-            if not source_lines:
-                source_lines = None
-        except TypeError:
-            source_lines = None
-
-        # Initialize globals, and merge in extraglobs.
-        if globs is None:
-            if module is None:
-                globs = {}
-            else:
-                globs = module.__dict__.copy()
-        else:
-            globs = globs.copy()
-        if extraglobs is not None:
-            globs.update(extraglobs)
-
-        # Recursively expore `obj`, extracting DocTests.
-        tests = []
-        self._find(tests, obj, name, module, source_lines, globs, {})
-        return tests
-
-    def _filter(self, obj, prefix, base):
-        """
-        Return true if the given object should not be examined.
-        """
-        return (self._namefilter is not None and
-                self._namefilter(prefix, base))
-
-    def _from_module(self, module, object):
-        """
-        Return true if the given object is defined in the given
-        module.
-        """
-        if module is None:
-            return True
-        elif inspect.isfunction(object):
-            return module.__dict__ is object.func_globals
-        elif inspect.isclass(object):
-            return module.__name__ == object.__module__
-        elif inspect.getmodule(object) is not None:
-            return module is inspect.getmodule(object)
-        elif hasattr(object, '__module__'):
-            return module.__name__ == object.__module__
-        elif isinstance(object, property):
-            return True # [XX] no way not be sure.
-        else:
-            raise ValueError("object must be a class or function")
-
-    def _find(self, tests, obj, name, module, source_lines, globs, seen):
-        """
-        Find tests for the given object and any contained objects, and
-        add them to `tests`.
-        """
-        if self._verbose:
-            print 'Finding tests in %s' % name
-
-        # If we've already processed this object, then ignore it.
-        if id(obj) in seen:
-            return
-        seen[id(obj)] = 1
-
-        # Find a test for this object, and add it to the list of tests.
-        test = self._get_test(obj, name, module, globs, source_lines)
-        if test is not None:
-            tests.append(test)
-
-        # Look for tests in a module's contained objects.
-        if inspect.ismodule(obj) and self._recurse:
-            for valname, val in obj.__dict__.items():
-                # Check if this contained object should be ignored.
-                if self._filter(val, name, valname):
-                    continue
-                valname = '%s.%s' % (name, valname)
-                # Recurse to functions & classes.
-                if ((inspect.isfunction(val) or inspect.isclass(val)) and
-                    self._from_module(module, val)):
-                    self._find(tests, val, valname, module, source_lines,
-                               globs, seen)
-
-        # Look for tests in a module's __test__ dictionary.
-        if inspect.ismodule(obj) and self._recurse:
-            for valname, val in getattr(obj, '__test__', {}).items():
-                if not isinstance(valname, basestring):
-                    raise ValueError("DocTestFinder.find: __test__ keys "
-                                     "must be strings: %r" %
-                                     (type(valname),))
-                if not (inspect.isfunction(val) or inspect.isclass(val) or
-                        inspect.ismethod(val) or inspect.ismodule(val) or
-                        isinstance(val, basestring)):
-                    raise ValueError("DocTestFinder.find: __test__ values "
-                                     "must be strings, functions, methods, "
-                                     "classes, or modules: %r" %
-                                     (type(val),))
-                valname = '%s.__test__.%s' % (name, valname)
-                self._find(tests, val, valname, module, source_lines,
-                           globs, seen)
-
-        # Look for tests in a class's contained objects.
-        if inspect.isclass(obj) and self._recurse:
-            for valname, val in obj.__dict__.items():
-                # Check if this contained object should be ignored.
-                if self._filter(val, name, valname):
-                    continue
-                # Special handling for staticmethod/classmethod.
-                if isinstance(val, staticmethod):
-                    val = getattr(obj, valname)
-                if isinstance(val, classmethod):
-                    val = getattr(obj, valname).im_func
-
-                # Recurse to methods, properties, and nested classes.
-                if ((inspect.isfunction(val) or inspect.isclass(val) or
-                      isinstance(val, property)) and
-                      self._from_module(module, val)):
-                    valname = '%s.%s' % (name, valname)
-                    self._find(tests, val, valname, module, source_lines,
-                               globs, seen)
-
-    def _get_test(self, obj, name, module, globs, source_lines):
-        """
-        Return a DocTest for the given object, if it defines a docstring;
-        otherwise, return None.
-        """
-        # Extract the object's docstring.  If it doesn't have one,
-        # then return None (no test for this object).
-        if isinstance(obj, basestring):
-            docstring = obj
-        else:
-            try:
-                if obj.__doc__ is None:
-                    docstring = ''
-                else:
-                    docstring = obj.__doc__
-                    if not isinstance(docstring, basestring):
-                        docstring = str(docstring)
-            except (TypeError, AttributeError):
-                docstring = ''
-
-        # Find the docstring's location in the file.
-        lineno = self._find_lineno(obj, source_lines)
-
-        # Don't bother if the docstring is empty.
-        if self._exclude_empty and not docstring:
-            return None
-
-        # Return a DocTest for this object.
-        if module is None:
-            filename = None
-        else:
-            filename = getattr(module, '__file__', module.__name__)
-            if filename[-4:] in (".pyc", ".pyo"):
-                filename = filename[:-1]
-        return self._parser.get_doctest(docstring, globs, name,
-                                        filename, lineno)
-
-    def _find_lineno(self, obj, source_lines):
-        """
-        Return a line number of the given object's docstring.  Note:
-        this method assumes that the object has a docstring.
-        """
-        lineno = None
-
-        # Find the line number for modules.
-        if inspect.ismodule(obj):
-            lineno = 0
-
-        # Find the line number for classes.
-        # Note: this could be fooled if a class is defined multiple
-        # times in a single file.
-        if inspect.isclass(obj):
-            if source_lines is None:
-                return None
-            pat = re.compile(r'^\s*class\s*%s\b' %
-                             getattr(obj, '__name__', '-'))
-            for i, line in enumerate(source_lines):
-                if pat.match(line):
-                    lineno = i
-                    break
-
-        # Find the line number for functions & methods.
-        if inspect.ismethod(obj): obj = obj.im_func
-        if inspect.isfunction(obj): obj = obj.func_code
-        if inspect.istraceback(obj): obj = obj.tb_frame
-        if inspect.isframe(obj): obj = obj.f_code
-        if inspect.iscode(obj):
-            lineno = getattr(obj, 'co_firstlineno', None)-1
-
-        # Find the line number where the docstring starts.  Assume
-        # that it's the first line that begins with a quote mark.
-        # Note: this could be fooled by a multiline function
-        # signature, where a continuation line begins with a quote
-        # mark.
-        if lineno is not None:
-            if source_lines is None:
-                return lineno+1
-            pat = re.compile('(^|.*:)\s*\w*("|\')')
-            for lineno in range(lineno, len(source_lines)):
-                if pat.match(source_lines[lineno]):
-                    return lineno
-
-        # We couldn't find the line number.
-        return None
-
-######################################################################
-## 5. DocTest Runner
-######################################################################
-
-class DocTestRunner:
-    """
-    A class used to run DocTest test cases, and accumulate statistics.
-    The `run` method is used to process a single DocTest case.  It
-    returns a tuple `(f, t)`, where `t` is the number of test cases
-    tried, and `f` is the number of test cases that failed.
-
-        >>> tests = DocTestFinder().find(_TestClass)
-        >>> runner = DocTestRunner(verbose=False)
-        >>> for test in tests:
-        ...     print runner.run(test)
-        (0, 2)
-        (0, 1)
-        (0, 2)
-        (0, 2)
-
-    The `summarize` method prints a summary of all the test cases that
-    have been run by the runner, and returns an aggregated `(f, t)`
-    tuple:
-
-        >>> runner.summarize(verbose=1)
-        4 items passed all tests:
-           2 tests in _TestClass
-           2 tests in _TestClass.__init__
-           2 tests in _TestClass.get
-           1 tests in _TestClass.square
-        7 tests in 4 items.
-        7 passed and 0 failed.
-        Test passed.
-        (0, 7)
-
-    The aggregated number of tried examples and failed examples is
-    also available via the `tries` and `failures` attributes:
-
-        >>> runner.tries
-        7
-        >>> runner.failures
-        0
-
-    The comparison between expected outputs and actual outputs is done
-    by an `OutputChecker`.  This comparison may be customized with a
-    number of option flags; see the documentation for `testmod` for
-    more information.  If the option flags are insufficient, then the
-    comparison may also be customized by passing a subclass of
-    `OutputChecker` to the constructor.
-
-    The test runner's display output can be controlled in two ways.
-    First, an output function (`out) can be passed to
-    `TestRunner.run`; this function will be called with strings that
-    should be displayed.  It defaults to `sys.stdout.write`.  If
-    capturing the output is not sufficient, then the display output
-    can be also customized by subclassing DocTestRunner, and
-    overriding the methods `report_start`, `report_success`,
-    `report_unexpected_exception`, and `report_failure`.
-    """
-    # This divider string is used to separate failure messages, and to
-    # separate sections of the summary.
-    DIVIDER = "*" * 70
-
-    def __init__(self, checker=None, verbose=None, optionflags=0):
-        """
-        Create a new test runner.
-
-        Optional keyword arg `checker` is the `OutputChecker` that
-        should be used to compare the expected outputs and actual
-        outputs of doctest examples.
-
-        Optional keyword arg 'verbose' prints lots of stuff if true,
-        only failures if false; by default, it's true iff '-v' is in
-        sys.argv.
-
-        Optional argument `optionflags` can be used to control how the
-        test runner compares expected output to actual output, and how
-        it displays failures.  See the documentation for `testmod` for
-        more information.
-        """
-        self._checker = checker or OutputChecker()
-        if verbose is None:
-            verbose = '-v' in sys.argv
-        self._verbose = verbose
-        self.optionflags = optionflags
-        self.original_optionflags = optionflags
-
-        # Keep track of the examples we've run.
-        self.tries = 0
-        self.failures = 0
-        self._name2ft = {}
-
-        # Create a fake output target for capturing doctest output.
-        self._fakeout = _SpoofOut()
-
-    #/////////////////////////////////////////////////////////////////
-    # Reporting methods
-    #/////////////////////////////////////////////////////////////////
-
-    def report_start(self, out, test, example):
-        """
-        Report that the test runner is about to process the given
-        example.  (Only displays a message if verbose=True)
-        """
-        if self._verbose:
-            if example.want:
-                out('Trying:\n' + _indent(example.source) +
-                    'Expecting:\n' + _indent(example.want))
-            else:
-                out('Trying:\n' + _indent(example.source) +
-                    'Expecting nothing\n')
-
-    def report_success(self, out, test, example, got):
-        """
-        Report that the given example ran successfully.  (Only
-        displays a message if verbose=True)
-        """
-        if self._verbose:
-            out("ok\n")
-
-    def report_failure(self, out, test, example, got):
-        """
-        Report that the given example failed.
-        """
-        out(self._failure_header(test, example) +
-            self._checker.output_difference(example, got, self.optionflags))
-
-    def report_unexpected_exception(self, out, test, example, exc_info):
-        """
-        Report that the given example raised an unexpected exception.
-        """
-        out(self._failure_header(test, example) +
-            'Exception raised:\n' + _indent(_exception_traceback(exc_info)))
-
-    def _failure_header(self, test, example):
-        out = [self.DIVIDER]
-        if test.filename:
-            if test.lineno is not None and example.lineno is not None:
-                lineno = test.lineno + example.lineno + 1
-            else:
-                lineno = '?'
-            out.append('File "%s", line %s, in %s' %
-                       (test.filename, lineno, test.name))
-        else:
-            out.append('Line %s, in %s' % (example.lineno+1, test.name))
-        out.append('Failed example:')
-        source = example.source
-        out.append(_indent(source))
-        return '\n'.join(out)
-
-    #/////////////////////////////////////////////////////////////////
-    # DocTest Running
-    #/////////////////////////////////////////////////////////////////
-
-    def __run(self, test, compileflags, out):
-        """
-        Run the examples in `test`.  Write the outcome of each example
-        with one of the `DocTestRunner.report_*` methods, using the
-        writer function `out`.  `compileflags` is the set of compiler
-        flags that should be used to execute examples.  Return a tuple
-        `(f, t)`, where `t` is the number of examples tried, and `f`
-        is the number of examples that failed.  The examples are run
-        in the namespace `test.globs`.
-        """
-        # Keep track of the number of failures and tries.
-        failures = tries = 0
-
-        # Save the option flags (since option directives can be used
-        # to modify them).
-        original_optionflags = self.optionflags
-
-        SUCCESS, FAILURE, BOOM = range(3) # `outcome` state
-
-        check = self._checker.check_output
-
-        # Process each example.
-        for examplenum, example in enumerate(test.examples):
-
-            # If REPORT_ONLY_FIRST_FAILURE is set, then supress
-            # reporting after the first failure.
-            quiet = (self.optionflags & REPORT_ONLY_FIRST_FAILURE and
-                     failures > 0)
-
-            # Merge in the example's options.
-            self.optionflags = original_optionflags
-            if example.options:
-                for (optionflag, val) in example.options.items():
-                    if val:
-                        self.optionflags |= optionflag
-                    else:
-                        self.optionflags &= ~optionflag
-
-            # Record that we started this example.
-            tries += 1
-            if not quiet:
-                self.report_start(out, test, example)
-
-            # Use a special filename for compile(), so we can retrieve
-            # the source code during interactive debugging (see
-            # __patched_linecache_getlines).
-            filename = '<doctest %s[%d]>' % (test.name, examplenum)
-
-            # Run the example in the given context (globs), and record
-            # any exception that gets raised.  (But don't intercept
-            # keyboard interrupts.)
-            try:
-                # Don't blink!  This is where the user's code gets run.
-                exec compile(example.source, filename, "single",
-                             compileflags, 1) in test.globs
-                self.debugger.set_continue() # ==== Example Finished ====
-                exception = None
-            except KeyboardInterrupt:
-                raise
-            except:
-                exception = sys.exc_info()
-                self.debugger.set_continue() # ==== Example Finished ====
-
-            got = self._fakeout.getvalue()  # the actual output
-            self._fakeout.truncate(0)
-            outcome = FAILURE   # guilty until proved innocent or insane
-
-            # If the example executed without raising any exceptions,
-            # verify its output.
-            if exception is None:
-                if check(example.want, got, self.optionflags):
-                    outcome = SUCCESS
-
-            # The example raised an exception:  check if it was expected.
-            else:
-                exc_info = sys.exc_info()
-                exc_msg = traceback.format_exception_only(*exc_info[:2])[-1]
-                if not quiet:
-                    got += _exception_traceback(exc_info)
-
-                # If `example.exc_msg` is None, then we weren't expecting
-                # an exception.
-                if example.exc_msg is None:
-                    outcome = BOOM
-
-                # We expected an exception:  see whether it matches.
-                elif check(example.exc_msg, exc_msg, self.optionflags):
-                    outcome = SUCCESS
-
-                # Another chance if they didn't care about the detail.
-                elif self.optionflags & IGNORE_EXCEPTION_DETAIL:
-                    m1 = re.match(r'[^:]*:', example.exc_msg)
-                    m2 = re.match(r'[^:]*:', exc_msg)
-                    if m1 and m2 and check(m1.group(0), m2.group(0),
-                                           self.optionflags):
-                        outcome = SUCCESS
-
-            # Report the outcome.
-            if outcome is SUCCESS:
-                if not quiet:
-                    self.report_success(out, test, example, got)
-            elif outcome is FAILURE:
-                if not quiet:
-                    self.report_failure(out, test, example, got)
-                failures += 1
-            elif outcome is BOOM:
-                if not quiet:
-                    self.report_unexpected_exception(out, test, example,
-                                                     exc_info)
-                failures += 1
-            else:
-                assert False, ("unknown outcome", outcome)
-
-        # Restore the option flags (in case they were modified)
-        self.optionflags = original_optionflags
-
-        # Record and return the number of failures and tries.
-        self.__record_outcome(test, failures, tries)
-        return failures, tries
-
-    def __record_outcome(self, test, f, t):
-        """
-        Record the fact that the given DocTest (`test`) generated `f`
-        failures out of `t` tried examples.
-        """
-        f2, t2 = self._name2ft.get(test.name, (0,0))
-        self._name2ft[test.name] = (f+f2, t+t2)
-        self.failures += f
-        self.tries += t
-
-    __LINECACHE_FILENAME_RE = re.compile(r'<doctest '
-                                         r'(?P<name>[\w\.]+)'
-                                         r'\[(?P<examplenum>\d+)\]>$')
-    def __patched_linecache_getlines(self, filename, module_globals=None):
-        m = self.__LINECACHE_FILENAME_RE.match(filename)
-        if m and m.group('name') == self.test.name:
-            example = self.test.examples[int(m.group('examplenum'))]
-            return example.source.splitlines(True)
-        else:
-            return self.save_linecache_getlines(filename)#?, module_globals)
-
-    def run(self, test, compileflags=None, out=None, clear_globs=True):
-        """
-        Run the examples in `test`, and display the results using the
-        writer function `out`.
-
-        The examples are run in the namespace `test.globs`.  If
-        `clear_globs` is true (the default), then this namespace will
-        be cleared after the test runs, to help with garbage
-        collection.  If you would like to examine the namespace after
-        the test completes, then use `clear_globs=False`.
-
-        `compileflags` gives the set of flags that should be used by
-        the Python compiler when running the examples.  If not
-        specified, then it will default to the set of future-import
-        flags that apply to `globs`.
-
-        The output of each example is checked using
-        `DocTestRunner.check_output`, and the results are formatted by
-        the `DocTestRunner.report_*` methods.
-        """
-        self.test = test
-
-        if compileflags is None:
-            compileflags = _extract_future_flags(test.globs)
-
-        save_stdout = sys.stdout
-        if out is None:
-            out = save_stdout.write
-        sys.stdout = self._fakeout
-
-        # Patch pdb.set_trace to restore sys.stdout during interactive
-        # debugging (so it's not still redirected to self._fakeout).
-        # Note that the interactive output will go to *our*
-        # save_stdout, even if that's not the real sys.stdout; this
-        # allows us to write test cases for the set_trace behavior.
-        save_set_trace = pdb.set_trace
-        self.debugger = _OutputRedirectingPdb(save_stdout)
-        self.debugger.reset()
-        pdb.set_trace = self.debugger.set_trace
-
-        # Patch linecache.getlines, so we can see the example's source
-        # when we're inside the debugger.
-        self.save_linecache_getlines = linecache.getlines
-        linecache.getlines = self.__patched_linecache_getlines
-
-        try:
-            return self.__run(test, compileflags, out)
-        finally:
-            sys.stdout = save_stdout
-            pdb.set_trace = save_set_trace
-            linecache.getlines = self.save_linecache_getlines
-            if clear_globs:
-                test.globs.clear()
-
-    #/////////////////////////////////////////////////////////////////
-    # Summarization
-    #/////////////////////////////////////////////////////////////////
-    def summarize(self, verbose=None):
-        """
-        Print a summary of all the test cases that have been run by
-        this DocTestRunner, and return a tuple `(f, t)`, where `f` is
-        the total number of failed examples, and `t` is the total
-        number of tried examples.
-
-        The optional `verbose` argument controls how detailed the
-        summary is.  If the verbosity is not specified, then the
-        DocTestRunner's verbosity is used.
-        """
-        if verbose is None:
-            verbose = self._verbose
-        notests = []
-        passed = []
-        failed = []
-        totalt = totalf = 0
-        for x in self._name2ft.items():
-            name, (f, t) = x
-            assert f <= t
-            totalt += t
-            totalf += f
-            if t == 0:
-                notests.append(name)
-            elif f == 0:
-                passed.append( (name, t) )
-            else:
-                failed.append(x)
-        if verbose:
-            if notests:
-                print len(notests), "items had no tests:"
-                notests.sort()
-                for thing in notests:
-                    print "   ", thing
-            if passed:
-                print len(passed), "items passed all tests:"
-                passed.sort()
-                for thing, count in passed:
-                    print " %3d tests in %s" % (count, thing)
-        if failed:
-            print self.DIVIDER
-            print len(failed), "items had failures:"
-            failed.sort()
-            for thing, (f, t) in failed:
-                print " %3d of %3d in %s" % (f, t, thing)
-        if verbose:
-            print totalt, "tests in", len(self._name2ft), "items."
-            print totalt - totalf, "passed and", totalf, "failed."
-        if totalf:
-            print "***Test Failed***", totalf, "failures."
-        elif verbose:
-            print "Test passed."
-        return totalf, totalt
-
-    #/////////////////////////////////////////////////////////////////
-    # Backward compatibility cruft to maintain doctest.master.
-    #/////////////////////////////////////////////////////////////////
-    def merge(self, other):
-        d = self._name2ft
-        for name, (f, t) in other._name2ft.items():
-            if name in d:
-                print "*** DocTestRunner.merge: '" + name + "' in both" \
-                    " testers; summing outcomes."
-                f2, t2 = d[name]
-                f = f + f2
-                t = t + t2
-            d[name] = f, t
-
-class OutputChecker:
-    """
-    A class used to check the whether the actual output from a doctest
-    example matches the expected output.  `OutputChecker` defines two
-    methods: `check_output`, which compares a given pair of outputs,
-    and returns true if they match; and `output_difference`, which
-    returns a string describing the differences between two outputs.
-    """
-    def check_output(self, want, got, optionflags):
-        """
-        Return True iff the actual output from an example (`got`)
-        matches the expected output (`want`).  These strings are
-        always considered to match if they are identical; but
-        depending on what option flags the test runner is using,
-        several non-exact match types are also possible.  See the
-        documentation for `TestRunner` for more information about
-        option flags.
-        """
-        # Handle the common case first, for efficiency:
-        # if they're string-identical, always return true.
-        if got == want:
-            return True
-
-        # The values True and False replaced 1 and 0 as the return
-        # value for boolean comparisons in Python 2.3.
-        if not (optionflags & DONT_ACCEPT_TRUE_FOR_1):
-            if (got,want) == ("True\n", "1\n"):
-                return True
-            if (got,want) == ("False\n", "0\n"):
-                return True
-
-        # <BLANKLINE> can be used as a special sequence to signify a
-        # blank line, unless the DONT_ACCEPT_BLANKLINE flag is used.
-        if not (optionflags & DONT_ACCEPT_BLANKLINE):
-            # Replace <BLANKLINE> in want with a blank line.
-            want = re.sub('(?m)^%s\s*?$' % re.escape(BLANKLINE_MARKER),
-                          '', want)
-            # If a line in got contains only spaces, then remove the
-            # spaces.
-            got = re.sub('(?m)^\s*?$', '', got)
-            if got == want:
-                return True
-
-        # This flag causes doctest to ignore any differences in the
-        # contents of whitespace strings.  Note that this can be used
-        # in conjunction with the ELLIPSIS flag.
-        if optionflags & NORMALIZE_WHITESPACE:
-            got = ' '.join(got.split())
-            want = ' '.join(want.split())
-            if got == want:
-                return True
-
-        # The ELLIPSIS flag says to let the sequence "..." in `want`
-        # match any substring in `got`.
-        if optionflags & ELLIPSIS:
-            if _ellipsis_match(want, got):
-                return True
-
-        # We didn't find any match; return false.
-        return False
-
-    # Should we do a fancy diff?
-    def _do_a_fancy_diff(self, want, got, optionflags):
-        # Not unless they asked for a fancy diff.
-        if not optionflags & (REPORT_UDIFF |
-                              REPORT_CDIFF |
-                              REPORT_NDIFF):
-            return False
-
-        # If expected output uses ellipsis, a meaningful fancy diff is
-        # too hard ... or maybe not.  In two real-life failures Tim saw,
-        # a diff was a major help anyway, so this is commented out.
-        # [todo] _ellipsis_match() knows which pieces do and don't match,
-        # and could be the basis for a kick-ass diff in this case.
-        ##if optionflags & ELLIPSIS and ELLIPSIS_MARKER in want:
-        ##    return False
-
-        # ndiff does intraline difference marking, so can be useful even
-        # for 1-line differences.
-        if optionflags & REPORT_NDIFF:
-            return True
-
-        # The other diff types need at least a few lines to be helpful.
-        return want.count('\n') > 2 and got.count('\n') > 2
-
-    def output_difference(self, example, got, optionflags):
-        """
-        Return a string describing the differences between the
-        expected output for a given example (`example`) and the actual
-        output (`got`).  `optionflags` is the set of option flags used
-        to compare `want` and `got`.
-        """
-        want = example.want
-        # If <BLANKLINE>s are being used, then replace blank lines
-        # with <BLANKLINE> in the actual output string.
-        if not (optionflags & DONT_ACCEPT_BLANKLINE):
-            got = re.sub('(?m)^[ ]*(?=\n)', BLANKLINE_MARKER, got)
-
-        # Check if we should use diff.
-        if self._do_a_fancy_diff(want, got, optionflags):
-            # Split want & got into lines.
-            want_lines = want.splitlines(True)  # True == keep line ends
-            got_lines = got.splitlines(True)
-            # Use difflib to find their differences.
-            if optionflags & REPORT_UDIFF:
-                diff = difflib.unified_diff(want_lines, got_lines, n=2)
-                diff = list(diff)[2:] # strip the diff header
-                kind = 'unified diff with -expected +actual'
-            elif optionflags & REPORT_CDIFF:
-                diff = difflib.context_diff(want_lines, got_lines, n=2)
-                diff = list(diff)[2:] # strip the diff header
-                kind = 'context diff with expected followed by actual'
-            elif optionflags & REPORT_NDIFF:
-                engine = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
-                diff = list(engine.compare(want_lines, got_lines))
-                kind = 'ndiff with -expected +actual'
-            else:
-                assert 0, 'Bad diff option'
-            # Remove trailing whitespace on diff output.
-            diff = [line.rstrip() + '\n' for line in diff]
-            return 'Differences (%s):\n' % kind + _indent(''.join(diff))
-
-        # If we're not using diff, then simply list the expected
-        # output followed by the actual output.
-        if want and got:
-            return 'Expected:\n%sGot:\n%s' % (_indent(want), _indent(got))
-        elif want:
-            return 'Expected:\n%sGot nothing\n' % _indent(want)
-        elif got:
-            return 'Expected nothing\nGot:\n%s' % _indent(got)
-        else:
-            return 'Expected nothing\nGot nothing\n'
-
-class DocTestFailure(Exception):
-    """A DocTest example has failed in debugging mode.
-
-    The exception instance has variables:
-
-    - test: the DocTest object being run
-
-    - excample: the Example object that failed
-
-    - got: the actual output
-    """
-    def __init__(self, test, example, got):
-        self.test = test
-        self.example = example
-        self.got = got
-
-    def __str__(self):
-        return str(self.test)
-
-class UnexpectedException(Exception):
-    """A DocTest example has encountered an unexpected exception
-
-    The exception instance has variables:
-
-    - test: the DocTest object being run
-
-    - excample: the Example object that failed
-
-    - exc_info: the exception info
-    """
-    def __init__(self, test, example, exc_info):
-        self.test = test
-        self.example = example
-        self.exc_info = exc_info
-
-    def __str__(self):
-        return str(self.test)
-
-class DebugRunner(DocTestRunner):
-    r"""Run doc tests but raise an exception as soon as there is a failure.
-
-       If an unexpected exception occurs, an UnexpectedException is raised.
-       It contains the test, the example, and the original exception:
-
-         >>> runner = DebugRunner(verbose=False)
-         >>> test = DocTestParser().get_doctest('>>> raise KeyError\n42',
-         ...                                    {}, 'foo', 'foo.py', 0)
-         >>> try:
-         ...     runner.run(test)
-         ... except UnexpectedException, failure:
-         ...     pass
-
-         >>> failure.test is test
-         True
-
-         >>> failure.example.want
-         '42\n'
-
-         >>> exc_info = failure.exc_info
-         >>> raise exc_info[0], exc_info[1], exc_info[2]
-         Traceback (most recent call last):
-         ...
-         KeyError
-
-       We wrap the original exception to give the calling application
-       access to the test and example information.
-
-       If the output doesn't match, then a DocTestFailure is raised:
-
-         >>> test = DocTestParser().get_doctest('''
-         ...      >>> x = 1
-         ...      >>> x
-         ...      2
-         ...      ''', {}, 'foo', 'foo.py', 0)
-
-         >>> try:
-         ...    runner.run(test)
-         ... except DocTestFailure, failure:
-         ...    pass
-
-       DocTestFailure objects provide access to the test:
-
-         >>> failure.test is test
-         True
-
-       As well as to the example:
-
-         >>> failure.example.want
-         '2\n'
-
-       and the actual output:
-
-         >>> failure.got
-         '1\n'
-
-       If a failure or error occurs, the globals are left intact:
-
-         >>> del test.globs['__builtins__']
-         >>> test.globs
-         {'x': 1}
-
-         >>> test = DocTestParser().get_doctest('''
-         ...      >>> x = 2
-         ...      >>> raise KeyError
-         ...      ''', {}, 'foo', 'foo.py', 0)
-
-         >>> runner.run(test)
-         Traceback (most recent call last):
-         ...
-         UnexpectedException: <DocTest foo from foo.py:0 (2 examples)>
-
-         >>> del test.globs['__builtins__']
-         >>> test.globs
-         {'x': 2}
-
-       But the globals are cleared if there is no error:
-
-         >>> test = DocTestParser().get_doctest('''
-         ...      >>> x = 2
-         ...      ''', {}, 'foo', 'foo.py', 0)
-
-         >>> runner.run(test)
-         (0, 1)
-
-         >>> test.globs
-         {}
-
-       """
-
-    def run(self, test, compileflags=None, out=None, clear_globs=True):
-        r = DocTestRunner.run(self, test, compileflags, out, False)
-        if clear_globs:
-            test.globs.clear()
-        return r
-
-    def report_unexpected_exception(self, out, test, example, exc_info):
-        raise UnexpectedException(test, example, exc_info)
-
-    def report_failure(self, out, test, example, got):
-        raise DocTestFailure(test, example, got)
-
-######################################################################
-## 6. Test Functions
-######################################################################
-# These should be backwards compatible.
-
-# For backward compatibility, a global instance of a DocTestRunner
-# class, updated by testmod.
-master = None
-
-def testmod(m=None, name=None, globs=None, verbose=None, isprivate=None,
-            report=True, optionflags=0, extraglobs=None,
-            raise_on_error=False, exclude_empty=False):
-    """m=None, name=None, globs=None, verbose=None, isprivate=None,
-       report=True, optionflags=0, extraglobs=None, raise_on_error=False,
-       exclude_empty=False
-
-    Test examples in docstrings in functions and classes reachable
-    from module m (or the current module if m is not supplied), starting
-    with m.__doc__.  Unless isprivate is specified, private names
-    are not skipped.
-
-    Also test examples reachable from dict m.__test__ if it exists and is
-    not None.  m.__test__ maps names to functions, classes and strings;
-    function and class docstrings are tested even if the name is private;
-    strings are tested directly, as if they were docstrings.
-
-    Return (#failures, #tests).
-
-    See doctest.__doc__ for an overview.
-
-    Optional keyword arg "name" gives the name of the module; by default
-    use m.__name__.
-
-    Optional keyword arg "globs" gives a dict to be used as the globals
-    when executing examples; by default, use m.__dict__.  A copy of this
-    dict is actually used for each docstring, so that each docstring's
-    examples start with a clean slate.
-
-    Optional keyword arg "extraglobs" gives a dictionary that should be
-    merged into the globals that are used to execute examples.  By
-    default, no extra globals are used.  This is new in 2.4.
-
-    Optional keyword arg "verbose" prints lots of stuff if true, prints
-    only failures if false; by default, it's true iff "-v" is in sys.argv.
-
-    Optional keyword arg "report" prints a summary at the end when true,
-    else prints nothing at the end.  In verbose mode, the summary is
-    detailed, else very brief (in fact, empty if all tests passed).
-
-    Optional keyword arg "optionflags" or's together module constants,
-    and defaults to 0.  This is new in 2.3.  Possible values (see the
-    docs for details):
-
-        DONT_ACCEPT_TRUE_FOR_1
-        DONT_ACCEPT_BLANKLINE
-        NORMALIZE_WHITESPACE
-        ELLIPSIS
-        IGNORE_EXCEPTION_DETAIL
-        REPORT_UDIFF
-        REPORT_CDIFF
-        REPORT_NDIFF
-        REPORT_ONLY_FIRST_FAILURE
-
-    Optional keyword arg "raise_on_error" raises an exception on the
-    first unexpected exception or failure. This allows failures to be
-    post-mortem debugged.
-
-    Deprecated in Python 2.4:
-    Optional keyword arg "isprivate" specifies a function used to
-    determine whether a name is private.  The default function is
-    treat all functions as public.  Optionally, "isprivate" can be
-    set to doctest.is_private to skip over functions marked as private
-    using the underscore naming convention; see its docs for details.
-
-    Advanced tomfoolery:  testmod runs methods of a local instance of
-    class doctest.Tester, then merges the results into (or creates)
-    global Tester instance doctest.master.  Methods of doctest.master
-    can be called directly too, if you want to do something unusual.
-    Passing report=0 to testmod is especially useful then, to delay
-    displaying a summary.  Invoke doctest.master.summarize(verbose)
-    when you're done fiddling.
-    """
-    global master
-
-    if isprivate is not None:
-        warnings.warn("the isprivate argument is deprecated; "
-                      "examine DocTestFinder.find() lists instead",
-                      DeprecationWarning)
-
-    # If no module was given, then use __main__.
-    if m is None:
-        # DWA - m will still be None if this wasn't invoked from the command
-        # line, in which case the following TypeError is about as good an error
-        # as we should expect
-        m = sys.modules.get('__main__')
-
-    # Check that we were actually given a module.
-    if not inspect.ismodule(m):
-        raise TypeError("testmod: module required; %r" % (m,))
-
-    # If no name was given, then use the module's name.
-    if name is None:
-        name = m.__name__
-
-    # Find, parse, and run all tests in the given module.
-    finder = DocTestFinder(_namefilter=isprivate, exclude_empty=exclude_empty)
-
-    if raise_on_error:
-        runner = DebugRunner(verbose=verbose, optionflags=optionflags)
-    else:
-        runner = DocTestRunner(verbose=verbose, optionflags=optionflags)
-
-    for test in finder.find(m, name, globs=globs, extraglobs=extraglobs):
-        runner.run(test)
-
-    if report:
-        runner.summarize()
-
-    if master is None:
-        master = runner
-    else:
-        master.merge(runner)
-
-    return runner.failures, runner.tries
-
-def testfile(filename, module_relative=True, name=None, package=None,
-             globs=None, verbose=None, report=True, optionflags=0,
-             extraglobs=None, raise_on_error=False, parser=DocTestParser()):
-    """
-    Test examples in the given file.  Return (#failures, #tests).
-
-    Optional keyword arg "module_relative" specifies how filenames
-    should be interpreted:
-
-      - If "module_relative" is True (the default), then "filename"
-         specifies a module-relative path.  By default, this path is
-         relative to the calling module's directory; but if the
-         "package" argument is specified, then it is relative to that
-         package.  To ensure os-independence, "filename" should use
-         "/" characters to separate path segments, and should not
-         be an absolute path (i.e., it may not begin with "/").
-
-      - If "module_relative" is False, then "filename" specifies an
-        os-specific path.  The path may be absolute or relative (to
-        the current working directory).
-
-    Optional keyword arg "name" gives the name of the test; by default
-    use the file's basename.
-
-    Optional keyword argument "package" is a Python package or the
-    name of a Python package whose directory should be used as the
-    base directory for a module relative filename.  If no package is
-    specified, then the calling module's directory is used as the base
-    directory for module relative filenames.  It is an error to
-    specify "package" if "module_relative" is False.
-
-    Optional keyword arg "globs" gives a dict to be used as the globals
-    when executing examples; by default, use {}.  A copy of this dict
-    is actually used for each docstring, so that each docstring's
-    examples start with a clean slate.
-
-    Optional keyword arg "extraglobs" gives a dictionary that should be
-    merged into the globals that are used to execute examples.  By
-    default, no extra globals are used.
-
-    Optional keyword arg "verbose" prints lots of stuff if true, prints
-    only failures if false; by default, it's true iff "-v" is in sys.argv.
-
-    Optional keyword arg "report" prints a summary at the end when true,
-    else prints nothing at the end.  In verbose mode, the summary is
-    detailed, else very brief (in fact, empty if all tests passed).
-
-    Optional keyword arg "optionflags" or's together module constants,
-    and defaults to 0.  Possible values (see the docs for details):
-
-        DONT_ACCEPT_TRUE_FOR_1
-        DONT_ACCEPT_BLANKLINE
-        NORMALIZE_WHITESPACE
-        ELLIPSIS
-        IGNORE_EXCEPTION_DETAIL
-        REPORT_UDIFF
-        REPORT_CDIFF
-        REPORT_NDIFF
-        REPORT_ONLY_FIRST_FAILURE
-
-    Optional keyword arg "raise_on_error" raises an exception on the
-    first unexpected exception or failure. This allows failures to be
-    post-mortem debugged.
-
-    Optional keyword arg "parser" specifies a DocTestParser (or
-    subclass) that should be used to extract tests from the files.
-
-    Advanced tomfoolery:  testmod runs methods of a local instance of
-    class doctest.Tester, then merges the results into (or creates)
-    global Tester instance doctest.master.  Methods of doctest.master
-    can be called directly too, if you want to do something unusual.
-    Passing report=0 to testmod is especially useful then, to delay
-    displaying a summary.  Invoke doctest.master.summarize(verbose)
-    when you're done fiddling.
-    """
-    global master
-
-    if package and not module_relative:
-        raise ValueError("Package may only be specified for module-"
-                         "relative paths.")
-
-    # Relativize the path
-    if module_relative:
-        package = _normalize_module(package)
-        filename = _module_relative_path(package, filename)
-
-    # If no name was given, then use the file's name.
-    if name is None:
-        name = os.path.basename(filename)
-
-    # Assemble the globals.
-    if globs is None:
-        globs = {}
-    else:
-        globs = globs.copy()
-    if extraglobs is not None:
-        globs.update(extraglobs)
-
-    if raise_on_error:
-        runner = DebugRunner(verbose=verbose, optionflags=optionflags)
-    else:
-        runner = DocTestRunner(verbose=verbose, optionflags=optionflags)
-
-    # Read the file, convert it to a test, and run it.
-    s = open(filename).read()
-    test = parser.get_doctest(s, globs, name, filename, 0)
-    runner.run(test)
-
-    if report:
-        runner.summarize()
-
-    if master is None:
-        master = runner
-    else:
-        master.merge(runner)
-
-    return runner.failures, runner.tries
-
-def run_docstring_examples(f, globs, verbose=False, name="NoName",
-                           compileflags=None, optionflags=0):
-    """
-    Test examples in the given object's docstring (`f`), using `globs`
-    as globals.  Optional argument `name` is used in failure messages.
-    If the optional argument `verbose` is true, then generate output
-    even if there are no failures.
-
-    `compileflags` gives the set of flags that should be used by the
-    Python compiler when running the examples.  If not specified, then
-    it will default to the set of future-import flags that apply to
-    `globs`.
-
-    Optional keyword arg `optionflags` specifies options for the
-    testing and output.  See the documentation for `testmod` for more
-    information.
-    """
-    # Find, parse, and run all tests in the given module.
-    finder = DocTestFinder(verbose=verbose, recurse=False)
-    runner = DocTestRunner(verbose=verbose, optionflags=optionflags)
-    for test in finder.find(f, name, globs=globs):
-        runner.run(test, compileflags=compileflags)
-
-######################################################################
-## 7. Tester
-######################################################################
-# This is provided only for backwards compatibility.  It's not
-# actually used in any way.
-
-class Tester:
-    def __init__(self, mod=None, globs=None, verbose=None,
-                 isprivate=None, optionflags=0):
-
-        warnings.warn("class Tester is deprecated; "
-                      "use class doctest.DocTestRunner instead",
-                      DeprecationWarning, stacklevel=2)
-        if mod is None and globs is None:
-            raise TypeError("Tester.__init__: must specify mod or globs")
-        if mod is not None and not inspect.ismodule(mod):
-            raise TypeError("Tester.__init__: mod must be a module; %r" %
-                            (mod,))
-        if globs is None:
-            globs = mod.__dict__
-        self.globs = globs
-
-        self.verbose = verbose
-        self.isprivate = isprivate
-        self.optionflags = optionflags
-        self.testfinder = DocTestFinder(_namefilter=isprivate)
-        self.testrunner = DocTestRunner(verbose=verbose,
-                                        optionflags=optionflags)
-
-    def runstring(self, s, name):
-        test = DocTestParser().get_doctest(s, self.globs, name, None, None)
-        if self.verbose:
-            print "Running string", name
-        (f,t) = self.testrunner.run(test)
-        if self.verbose:
-            print f, "of", t, "examples failed in string", name
-        return (f,t)
-
-    def rundoc(self, object, name=None, module=None):
-        f = t = 0
-        tests = self.testfinder.find(object, name, module=module,
-                                     globs=self.globs)
-        for test in tests:
-            (f2, t2) = self.testrunner.run(test)
-            (f,t) = (f+f2, t+t2)
-        return (f,t)
-
-    def rundict(self, d, name, module=None):
-        import new
-        m = new.module(name)
-        m.__dict__.update(d)
-        if module is None:
-            module = False
-        return self.rundoc(m, name, module)
-
-    def run__test__(self, d, name):
-        import new
-        m = new.module(name)
-        m.__test__ = d
-        return self.rundoc(m, name)
-
-    def summarize(self, verbose=None):
-        return self.testrunner.summarize(verbose)
-
-    def merge(self, other):
-        self.testrunner.merge(other.testrunner)
-
-######################################################################
-## 8. Unittest Support
-######################################################################
-
-_unittest_reportflags = 0
-
-def set_unittest_reportflags(flags):
-    """Sets the unittest option flags.
-
-    The old flag is returned so that a runner could restore the old
-    value if it wished to:
-
-      >>> old = _unittest_reportflags
-      >>> set_unittest_reportflags(REPORT_NDIFF |
-      ...                          REPORT_ONLY_FIRST_FAILURE) == old
-      True
-
-      >>> import doctest
-      >>> doctest._unittest_reportflags == (REPORT_NDIFF |
-      ...                                   REPORT_ONLY_FIRST_FAILURE)
-      True
-
-    Only reporting flags can be set:
-
-      >>> set_unittest_reportflags(ELLIPSIS)
-      Traceback (most recent call last):
-      ...
-      ValueError: ('Only reporting flags allowed', 8)
-
-      >>> set_unittest_reportflags(old) == (REPORT_NDIFF |
-      ...                                   REPORT_ONLY_FIRST_FAILURE)
-      True
-    """
-    global _unittest_reportflags
-
-    if (flags & REPORTING_FLAGS) != flags:
-        raise ValueError("Only reporting flags allowed", flags)
-    old = _unittest_reportflags
-    _unittest_reportflags = flags
-    return old
-
-
-class DocTestCase(unittest.TestCase):
-
-    def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
-                 checker=None):
-
-        unittest.TestCase.__init__(self)
-        self._dt_optionflags = optionflags
-        self._dt_checker = checker
-        self._dt_test = test
-        self._dt_setUp = setUp
-        self._dt_tearDown = tearDown
-
-    def setUp(self):
-        test = self._dt_test
-
-        if self._dt_setUp is not None:
-            self._dt_setUp(test)
-
-    def tearDown(self):
-        test = self._dt_test
-
-        if self._dt_tearDown is not None:
-            self._dt_tearDown(test)
-
-        test.globs.clear()
-
-    def runTest(self):
-        test = self._dt_test
-        old = sys.stdout
-        new = StringIO()
-        optionflags = self._dt_optionflags
-
-        if not (optionflags & REPORTING_FLAGS):
-            # The option flags don't include any reporting flags,
-            # so add the default reporting flags
-            optionflags |= _unittest_reportflags
-
-        runner = DocTestRunner(optionflags=optionflags,
-                               checker=self._dt_checker, verbose=False)
-
-        try:
-            runner.DIVIDER = "-"*70
-            failures, tries = runner.run(
-                test, out=new.write, clear_globs=False)
-        finally:
-            sys.stdout = old
-
-        if failures:
-            raise self.failureException(self.format_failure(new.getvalue()))
-
-    def format_failure(self, err):
-        test = self._dt_test
-        if test.lineno is None:
-            lineno = 'unknown line number'
-        else:
-            lineno = '%s' % test.lineno
-        lname = '.'.join(test.name.split('.')[-1:])
-        return ('Failed doctest test for %s\n'
-                '  File "%s", line %s, in %s\n\n%s'
-                % (test.name, test.filename, lineno, lname, err)
-                )
-
-    def debug(self):
-        r"""Run the test case without results and without catching exceptions
-
-           The unit test framework includes a debug method on test cases
-           and test suites to support post-mortem debugging.  The test code
-           is run in such a way that errors are not caught.  This way a
-           caller can catch the errors and initiate post-mortem debugging.
-
-           The DocTestCase provides a debug method that raises
-           UnexpectedException errors if there is an unexepcted
-           exception:
-
-             >>> test = DocTestParser().get_doctest('>>> raise KeyError\n42',
-             ...                {}, 'foo', 'foo.py', 0)
-             >>> case = DocTestCase(test)
-             >>> try:
-             ...     case.debug()
-             ... except UnexpectedException, failure:
-             ...     pass
-
-           The UnexpectedException contains the test, the example, and
-           the original exception:
-
-             >>> failure.test is test
-             True
-
-             >>> failure.example.want
-             '42\n'
-
-             >>> exc_info = failure.exc_info
-             >>> raise exc_info[0], exc_info[1], exc_info[2]
-             Traceback (most recent call last):
-             ...
-             KeyError
-
-           If the output doesn't match, then a DocTestFailure is raised:
-
-             >>> test = DocTestParser().get_doctest('''
-             ...      >>> x = 1
-             ...      >>> x
-             ...      2
-             ...      ''', {}, 'foo', 'foo.py', 0)
-             >>> case = DocTestCase(test)
-
-             >>> try:
-             ...    case.debug()
-             ... except DocTestFailure, failure:
-             ...    pass
-
-           DocTestFailure objects provide access to the test:
-
-             >>> failure.test is test
-             True
-
-           As well as to the example:
-
-             >>> failure.example.want
-             '2\n'
-
-           and the actual output:
-
-             >>> failure.got
-             '1\n'
-
-           """
-
-        self.setUp()
-        runner = DebugRunner(optionflags=self._dt_optionflags,
-                             checker=self._dt_checker, verbose=False)
-        runner.run(self._dt_test)
-        self.tearDown()
-
-    def id(self):
-        return self._dt_test.name
-
-    def __repr__(self):
-        name = self._dt_test.name.split('.')
-        return "%s (%s)" % (name[-1], '.'.join(name[:-1]))
-
-    __str__ = __repr__
-
-    def shortDescription(self):
-        return "Doctest: " + self._dt_test.name
-
-def DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None,
-                 **options):
-    """
-    Convert doctest tests for a module to a unittest test suite.
-
-    This converts each documentation string in a module that
-    contains doctest tests to a unittest test case.  If any of the
-    tests in a doc string fail, then the test case fails.  An exception
-    is raised showing the name of the file containing the test and a
-    (sometimes approximate) line number.
-
-    The `module` argument provides the module to be tested.  The argument
-    can be either a module or a module name.
-
-    If no argument is given, the calling module is used.
-
-    A number of options may be provided as keyword arguments:
-
-    setUp
-      A set-up function.  This is called before running the
-      tests in each file. The setUp function will be passed a DocTest
-      object.  The setUp function can access the test globals as the
-      globs attribute of the test passed.
-
-    tearDown
-      A tear-down function.  This is called after running the
-      tests in each file.  The tearDown function will be passed a DocTest
-      object.  The tearDown function can access the test globals as the
-      globs attribute of the test passed.
-
-    globs
-      A dictionary containing initial global variables for the tests.
-
-    optionflags
-       A set of doctest option flags expressed as an integer.
-    """
-
-    if test_finder is None:
-        test_finder = DocTestFinder()
-
-    module = _normalize_module(module)
-    tests = test_finder.find(module, globs=globs, extraglobs=extraglobs)
-    if globs is None:
-        globs = module.__dict__
-    if not tests:
-        # Why do we want to do this? Because it reveals a bug that might
-        # otherwise be hidden.
-        raise ValueError(module, "has no tests")
-
-    tests.sort()
-    suite = unittest.TestSuite()
-    for test in tests:
-        if len(test.examples) == 0:
-            continue
-        if not test.filename:
-            filename = module.__file__
-            if filename[-4:] in (".pyc", ".pyo"):
-                filename = filename[:-1]
-            test.filename = filename
-        suite.addTest(DocTestCase(test, **options))
-
-    return suite
-
-class DocFileCase(DocTestCase):
-
-    def id(self):
-        return '_'.join(self._dt_test.name.split('.'))
-
-    def __repr__(self):
-        return self._dt_test.filename
-    __str__ = __repr__
-
-    def format_failure(self, err):
-        return ('Failed doctest test for %s\n  File "%s", line 0\n\n%s'
-                % (self._dt_test.name, self._dt_test.filename, err)
-                )
-
-def DocFileTest(path, module_relative=True, package=None,
-                globs=None, parser=DocTestParser(), **options):
-    if globs is None:
-        globs = {}
-
-    if package and not module_relative:
-        raise ValueError("Package may only be specified for module-"
-                         "relative paths.")
-
-    # Relativize the path.
-    if module_relative:
-        package = _normalize_module(package)
-        path = _module_relative_path(package, path)
-
-    # Find the file and read it.
-    name = os.path.basename(path)
-    doc = open(path).read()
-
-    # Convert it to a test, and wrap it in a DocFileCase.
-    test = parser.get_doctest(doc, globs, name, path, 0)
-    return DocFileCase(test, **options)
-
-def DocFileSuite(*paths, **kw):
-    """A unittest suite for one or more doctest files.
-
-    The path to each doctest file is given as a string; the
-    interpretation of that string depends on the keyword argument
-    "module_relative".
-
-    A number of options may be provided as keyword arguments:
-
-    module_relative
-      If "module_relative" is True, then the given file paths are
-      interpreted as os-independent module-relative paths.  By
-      default, these paths are relative to the calling module's
-      directory; but if the "package" argument is specified, then
-      they are relative to that package.  To ensure os-independence,
-      "filename" should use "/" characters to separate path
-      segments, and may not be an absolute path (i.e., it may not
-      begin with "/").
-
-      If "module_relative" is False, then the given file paths are
-      interpreted as os-specific paths.  These paths may be absolute
-      or relative (to the current working directory).
-
-    package
-      A Python package or the name of a Python package whose directory
-      should be used as the base directory for module relative paths.
-      If "package" is not specified, then the calling module's
-      directory is used as the base directory for module relative
-      filenames.  It is an error to specify "package" if
-      "module_relative" is False.
-
-    setUp
-      A set-up function.  This is called before running the
-      tests in each file. The setUp function will be passed a DocTest
-      object.  The setUp function can access the test globals as the
-      globs attribute of the test passed.
-
-    tearDown
-      A tear-down function.  This is called after running the
-      tests in each file.  The tearDown function will be passed a DocTest
-      object.  The tearDown function can access the test globals as the
-      globs attribute of the test passed.
-
-    globs
-      A dictionary containing initial global variables for the tests.
-
-    optionflags
-      A set of doctest option flags expressed as an integer.
-
-    parser
-      A DocTestParser (or subclass) that should be used to extract
-      tests from the files.
-    """
-    suite = unittest.TestSuite()
-
-    # We do this here so that _normalize_module is called at the right
-    # level.  If it were called in DocFileTest, then this function
-    # would be the caller and we might guess the package incorrectly.
-    if kw.get('module_relative', True):
-        kw['package'] = _normalize_module(kw.get('package'))
-
-    for path in paths:
-        suite.addTest(DocFileTest(path, **kw))
-
-    return suite
-
-######################################################################
-## 9. Debugging Support
-######################################################################
-
-def script_from_examples(s):
-    r"""Extract script from text with examples.
-
-       Converts text with examples to a Python script.  Example input is
-       converted to regular code.  Example output and all other words
-       are converted to comments:
-
-       >>> text = '''
-       ...       Here are examples of simple math.
-       ...
-       ...           Python has super accurate integer addition
-       ...
-       ...           >>> 2 + 2
-       ...           5
-       ...
-       ...           And very friendly error messages:
-       ...
-       ...           >>> 1/0
-       ...           To Infinity
-       ...           And
-       ...           Beyond
-       ...
-       ...           You can use logic if you want:
-       ...
-       ...           >>> if 0:
-       ...           ...    blah
-       ...           ...    blah
-       ...           ...
-       ...
-       ...           Ho hum
-       ...           '''
-
-       >>> print script_from_examples(text)
-       # Here are examples of simple math.
-       #
-       #     Python has super accurate integer addition
-       #
-       2 + 2
-       # Expected:
-       ## 5
-       #
-       #     And very friendly error messages:
-       #
-       1/0
-       # Expected:
-       ## To Infinity
-       ## And
-       ## Beyond
-       #
-       #     You can use logic if you want:
-       #
-       if 0:
-          blah
-          blah
-       #
-       #     Ho hum
-       """
-    output = []
-    for piece in DocTestParser().parse(s):
-        if isinstance(piece, Example):
-            # Add the example's source code (strip trailing NL)
-            output.append(piece.source[:-1])
-            # Add the expected output:
-            want = piece.want
-            if want:
-                output.append('# Expected:')
-                output += ['## '+l for l in want.split('\n')[:-1]]
-        else:
-            # Add non-example text.
-            output += [_comment_line(l)
-                       for l in piece.split('\n')[:-1]]
-
-    # Trim junk on both ends.
-    while output and output[-1] == '#':
-        output.pop()
-    while output and output[0] == '#':
-        output.pop(0)
-    # Combine the output, and return it.
-    return '\n'.join(output)
-
-def testsource(module, name):
-    """Extract the test sources from a doctest docstring as a script.
-
-    Provide the module (or dotted name of the module) containing the
-    test to be debugged and the name (within the module) of the object
-    with the doc string with tests to be debugged.
-    """
-    module = _normalize_module(module)
-    tests = DocTestFinder().find(module)
-    test = [t for t in tests if t.name == name]
-    if not test:
-        raise ValueError(name, "not found in tests")
-    test = test[0]
-    testsrc = script_from_examples(test.docstring)
-    return testsrc
-
-def debug_src(src, pm=False, globs=None):
-    """Debug a single doctest docstring, in argument `src`'"""
-    testsrc = script_from_examples(src)
-    debug_script(testsrc, pm, globs)
-
-def debug_script(src, pm=False, globs=None):
-    "Debug a test script.  `src` is the script, as a string."
-    import pdb
-
-    # Note that tempfile.NameTemporaryFile() cannot be used.  As the
-    # docs say, a file so created cannot be opened by name a second time
-    # on modern Windows boxes, and execfile() needs to open it.
-    srcfilename = tempfile.mktemp(".py", "doctestdebug")
-    f = open(srcfilename, 'w')
-    f.write(src)
-    f.close()
-
-    try:
-        if globs:
-            globs = globs.copy()
-        else:
-            globs = {}
-
-        if pm:
-            try:
-                execfile(srcfilename, globs, globs)
-            except:
-                print sys.exc_info()[1]
-                pdb.post_mortem(sys.exc_info()[2])
-        else:
-            # Note that %r is vital here.  '%s' instead can, e.g., cause
-            # backslashes to get treated as metacharacters on Windows.
-            pdb.run("execfile(%r)" % srcfilename, globs, globs)
-
-    finally:
-        os.remove(srcfilename)
-
-def debug(module, name, pm=False):
-    """Debug a single doctest docstring.
-
-    Provide the module (or dotted name of the module) containing the
-    test to be debugged and the name (within the module) of the object
-    with the docstring with tests to be debugged.
-    """
-    module = _normalize_module(module)
-    testsrc = testsource(module, name)
-    debug_script(testsrc, pm, module.__dict__)
-
-######################################################################
-## 10. Example Usage
-######################################################################
-class _TestClass:
-    """
-    A pointless class, for sanity-checking of docstring testing.
-
-    Methods:
-        square()
-        get()
-
-    >>> _TestClass(13).get() + _TestClass(-12).get()
-    1
-    >>> hex(_TestClass(13).square().get())
-    '0xa9'
-    """
-
-    def __init__(self, val):
-        """val -> _TestClass object with associated value val.
-
-        >>> t = _TestClass(123)
-        >>> print t.get()
-        123
-        """
-
-        self.val = val
-
-    def square(self):
-        """square() -> square TestClass's associated value
-
-        >>> _TestClass(13).square().get()
-        169
-        """
-
-        self.val = self.val ** 2
-        return self
-
-    def get(self):
-        """get() -> return TestClass's associated value.
-
-        >>> x = _TestClass(-42)
-        >>> print x.get()
-        -42
-        """
-
-        return self.val
-
-__test__ = {"_TestClass": _TestClass,
-            "string": r"""
-                      Example of a string object, searched as-is.
-                      >>> x = 1; y = 2
-                      >>> x + y, x * y
-                      (3, 2)
-                      """,
-
-            "bool-int equivalence": r"""
-                                    In 2.2, boolean expressions displayed
-                                    0 or 1.  By default, we still accept
-                                    them.  This can be disabled by passing
-                                    DONT_ACCEPT_TRUE_FOR_1 to the new
-                                    optionflags argument.
-                                    >>> 4 == 4
-                                    1
-                                    >>> 4 == 4
-                                    True
-                                    >>> 4 > 4
-                                    0
-                                    >>> 4 > 4
-                                    False
-                                    """,
-
-            "blank lines": r"""
-                Blank lines can be marked with <BLANKLINE>:
-                    >>> print 'foo\n\nbar\n'
-                    foo
-                    <BLANKLINE>
-                    bar
-                    <BLANKLINE>
-            """,
-
-            "ellipsis": r"""
-                If the ellipsis flag is used, then '...' can be used to
-                elide substrings in the desired output:
-                    >>> print range(1000) #doctest: +ELLIPSIS
-                    [0, 1, 2, ..., 999]
-            """,
-
-            "whitespace normalization": r"""
-                If the whitespace normalization flag is used, then
-                differences in whitespace are ignored.
-                    >>> print range(30) #doctest: +NORMALIZE_WHITESPACE
-                    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
-                     15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
-                     27, 28, 29]
-            """,
-           }
-
-def _test():
-    r = unittest.TextTestRunner()
-    r.run(DocTestSuite())
-
-if __name__ == "__main__":
-    _test()
diff --git a/lib/paste/util/filemixin.py b/lib/paste/util/filemixin.py
@@ -1,53 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-class FileMixin(object):
-
-    """
-    Used to provide auxiliary methods to objects simulating files.
-    Objects must implement write, and read if they are input files.
-    Also they should implement close.
-
-    Other methods you may wish to override:
-    * flush()
-    * seek(offset[, whence])
-    * tell()
-    * truncate([size])
-
-    Attributes you may wish to provide:
-    * closed
-    * encoding (you should also respect that in write())
-    * mode
-    * newlines (hard to support)
-    * softspace
-    """
-
-    def flush(self):
-        pass
-
-    def next(self):
-        return self.readline()
-
-    def readline(self, size=None):
-        # @@: This is a lame implementation; but a buffer would probably
-        # be necessary for a better implementation
-        output = []
-        while 1:
-            next = self.read(1)
-            if not next:
-                return ''.join(output)
-            output.append(next)
-            if size and size > 0 and len(output) >= size:
-                return ''.join(output)
-            if next == '\n':
-                # @@: also \r?
-                return ''.join(output)
-
-    def xreadlines(self):
-        return self
-
-    def writelines(self, lines):
-        for line in lines:
-            self.write(line)
-
-    
diff --git a/lib/paste/util/finddata.py b/lib/paste/util/finddata.py
@@ -1,99 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-# Note: you may want to copy this into your setup.py file verbatim, as
-# you can't import this from another package, when you don't know if
-# that package is installed yet.
-
-import os
-import sys
-from fnmatch import fnmatchcase
-from distutils.util import convert_path
-
-# Provided as an attribute, so you can append to these instead
-# of replicating them:
-standard_exclude = ('*.py', '*.pyc', '*$py.class', '*~', '.*', '*.bak')
-standard_exclude_directories = ('.*', 'CVS', '_darcs', './build',
-                                './dist', 'EGG-INFO', '*.egg-info')
-
-def find_package_data(
-    where='.', package='',
-    exclude=standard_exclude,
-    exclude_directories=standard_exclude_directories,
-    only_in_packages=True,
-    show_ignored=False):
-    """
-    Return a dictionary suitable for use in ``package_data``
-    in a distutils ``setup.py`` file.
-
-    The dictionary looks like::
-
-        {'package': [files]}
-
-    Where ``files`` is a list of all the files in that package that
-    don't match anything in ``exclude``.
-
-    If ``only_in_packages`` is true, then top-level directories that
-    are not packages won't be included (but directories under packages
-    will).
-
-    Directories matching any pattern in ``exclude_directories`` will
-    be ignored; by default directories with leading ``.``, ``CVS``,
-    and ``_darcs`` will be ignored.
-
-    If ``show_ignored`` is true, then all the files that aren't
-    included in package data are shown on stderr (for debugging
-    purposes).
-
-    Note patterns use wildcards, or can be exact paths (including
-    leading ``./``), and all searching is case-insensitive.
-    """
-    
-    out = {}
-    stack = [(convert_path(where), '', package, only_in_packages)]
-    while stack:
-        where, prefix, package, only_in_packages = stack.pop(0)
-        for name in os.listdir(where):
-            fn = os.path.join(where, name)
-            if os.path.isdir(fn):
-                bad_name = False
-                for pattern in exclude_directories:
-                    if (fnmatchcase(name, pattern)
-                        or fn.lower() == pattern.lower()):
-                        bad_name = True
-                        if show_ignored:
-                            print >> sys.stderr, (
-                                "Directory %s ignored by pattern %s"
-                                % (fn, pattern))
-                        break
-                if bad_name:
-                    continue
-                if (os.path.isfile(os.path.join(fn, '__init__.py'))
-                    and not prefix):
-                    if not package:
-                        new_package = name
-                    else:
-                        new_package = package + '.' + name
-                    stack.append((fn, '', new_package, False))
-                else:
-                    stack.append((fn, prefix + name + '/', package, only_in_packages))
-            elif package or not only_in_packages:
-                # is a file
-                bad_name = False
-                for pattern in exclude:
-                    if (fnmatchcase(name, pattern)
-                        or fn.lower() == pattern.lower()):
-                        bad_name = True
-                        if show_ignored:
-                            print >> sys.stderr, (
-                                "File %s ignored by pattern %s"
-                                % (fn, pattern))
-                        break
-                if bad_name:
-                    continue
-                out.setdefault(package, []).append(prefix+name)
-    return out
-
-if __name__ == '__main__':
-    import pprint
-    pprint.pprint(
-        find_package_data(show_ignored=True))
diff --git a/lib/paste/util/findpackage.py b/lib/paste/util/findpackage.py
@@ -1,26 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-import sys
-import os
-
-def find_package(dir):
-    """
-    Given a directory, finds the equivalent package name.  If it
-    is directly in sys.path, returns ''.
-    """
-    dir = os.path.abspath(dir)
-    orig_dir = dir
-    path = map(os.path.abspath, sys.path)
-    packages = []
-    last_dir = None
-    while 1:
-        if dir in path:
-            return '.'.join(packages)
-        packages.insert(0, os.path.basename(dir))
-        dir = os.path.dirname(dir)
-        if last_dir == dir:
-            raise ValueError(
-                "%s is not under any path found in sys.path" % orig_dir)
-        last_dir = dir
-    
diff --git a/lib/paste/util/import_string.py b/lib/paste/util/import_string.py
@@ -1,95 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-"""
-'imports' a string -- converts a string to a Python object, importing
-any necessary modules and evaluating the expression.  Everything
-before the : in an import expression is the module path; everything
-after is an expression to be evaluated in the namespace of that
-module.
-
-Alternately, if no : is present, then import the modules and get the
-attributes as necessary.  Arbitrary expressions are not allowed in
-that case.
-"""
-
-def eval_import(s):
-    """
-    Import a module, or import an object from a module.
-
-    A module name like ``foo.bar:baz()`` can be used, where
-    ``foo.bar`` is the module, and ``baz()`` is an expression
-    evaluated in the context of that module.  Note this is not safe on
-    arbitrary strings because of the eval.
-    """
-    if ':' not in s:
-        return simple_import(s)
-    module_name, expr = s.split(':', 1)
-    module = import_module(module_name)
-    obj = eval(expr, module.__dict__)
-    return obj
-
-def simple_import(s):
-    """
-    Import a module, or import an object from a module.
-
-    A name like ``foo.bar.baz`` can be a module ``foo.bar.baz`` or a
-    module ``foo.bar`` with an object ``baz`` in it, or a module
-    ``foo`` with an object ``bar`` with an attribute ``baz``.
-    """
-    parts = s.split('.')
-    module = import_module(parts[0])
-    name = parts[0]
-    parts = parts[1:]
-    last_import_error = None
-    while parts:
-        name += '.' + parts[0]
-        try:
-            module = import_module(name)
-            parts = parts[1:]
-        except ImportError, e:
-            last_import_error = e
-            break
-    obj = module
-    while parts:
-        try:
-            obj = getattr(module, parts[0])
-        except AttributeError:
-            raise ImportError(
-                "Cannot find %s in module %r (stopped importing modules with error %s)" % (parts[0], module, last_import_error))
-        parts = parts[1:]
-    return obj
-
-def import_module(s):
-    """
-    Import a module.
-    """
-    mod = __import__(s)
-    parts = s.split('.')
-    for part in parts[1:]:
-        mod = getattr(mod, part)
-    return mod
-
-def try_import_module(module_name):
-    """
-    Imports a module, but catches import errors.  Only catches errors
-    when that module doesn't exist; if that module itself has an
-    import error it will still get raised.  Returns None if the module
-    doesn't exist.
-    """
-    try:
-        return import_module(module_name)
-    except ImportError, e:
-        if not getattr(e, 'args', None):
-            raise
-        desc = e.args[0]
-        if not desc.startswith('No module named '):
-            raise
-        desc = desc[len('No module named '):]
-        # If you import foo.bar.baz, the bad import could be any
-        # of foo.bar.baz, bar.baz, or baz; we'll test them all:
-        parts = module_name.split('.')
-        for i in range(len(parts)):
-            if desc == '.'.join(parts[i:]):
-                return None
-        raise
diff --git a/lib/paste/util/intset.py b/lib/paste/util/intset.py
@@ -1,511 +0,0 @@
-# -*- coding: iso-8859-15 -*-
-"""Immutable integer set type.
-
-Integer set class.
-
-Copyright (C) 2006, Heiko Wundram.
-Released under the MIT license.
-"""
-
-# Version information
-# -------------------
-
-__author__ = "Heiko Wundram <me@modelnine.org>"
-__version__ = "0.2"
-__revision__ = "6"
-__date__ = "2006-01-20"
-
-
-# Utility classes
-# ---------------
-
-class _Infinity(object):
-    """Internal type used to represent infinity values."""
-
-    __slots__ = ["_neg"]
-
-    def __init__(self,neg):
-        self._neg = neg
-
-    def __lt__(self,value):
-        if not isinstance(value,(int,long,_Infinity)):
-            return NotImplemented
-        return ( self._neg and
-                 not ( isinstance(value,_Infinity) and value._neg ) )
-
-    def __le__(self,value):
-        if not isinstance(value,(int,long,_Infinity)):
-            return NotImplemented
-        return self._neg
-
-    def __gt__(self,value):
-        if not isinstance(value,(int,long,_Infinity)):
-            return NotImplemented
-        return not ( self._neg or
-                     ( isinstance(value,_Infinity) and not value._neg ) )
-
-    def __ge__(self,value):
-        if not isinstance(value,(int,long,_Infinity)):
-            return NotImplemented
-        return not self._neg
-
-    def __eq__(self,value):
-        if not isinstance(value,(int,long,_Infinity)):
-            return NotImplemented
-        return isinstance(value,_Infinity) and self._neg == value._neg
-
-    def __ne__(self,value):
-        if not isinstance(value,(int,long,_Infinity)):
-            return NotImplemented
-        return not isinstance(value,_Infinity) or self._neg <> value._neg
-
-    def __repr__(self):
-        return "None"
-
-
-# Constants
-# ---------
-
-_MININF = _Infinity(True)
-_MAXINF = _Infinity(False)
-
-
-# Integer set class
-# -----------------
-
-class IntSet(object):
-    """Integer set class with efficient storage in a RLE format of ranges.
-    Supports minus and plus infinity in the range."""
-
-    __slots__ = ["_ranges","_min","_max","_hash"]
-
-    def __init__(self,*args,**kwargs):
-        """Initialize an integer set. The constructor accepts an unlimited
-        number of arguments that may either be tuples in the form of
-        (start,stop) where either start or stop may be a number or None to
-        represent maximum/minimum in that direction. The range specified by
-        (start,stop) is always inclusive (differing from the builtin range
-        operator).
-
-        Keyword arguments that can be passed to an integer set are min and
-        max, which specify the minimum and maximum number in the set,
-        respectively. You can also pass None here to represent minus or plus
-        infinity, which is also the default.
-        """
-
-        # Special case copy constructor.
-        if len(args) == 1 and isinstance(args[0],IntSet):
-            if kwargs:
-                raise ValueError("No keyword arguments for copy constructor.")
-            self._min = args[0]._min
-            self._max = args[0]._max
-            self._ranges = args[0]._ranges
-            self._hash = args[0]._hash
-            return
-
-        # Initialize set.
-        self._ranges = []
-
-        # Process keyword arguments.
-        self._min = kwargs.pop("min",_MININF)
-        self._max = kwargs.pop("max",_MAXINF)
-        if self._min is None:
-            self._min = _MININF
-        if self._max is None:
-            self._max = _MAXINF
-
-        # Check keyword arguments.
-        if kwargs:
-            raise ValueError("Invalid keyword argument.")
-        if not ( isinstance(self._min,(int,long)) or self._min is _MININF ):
-            raise TypeError("Invalid type of min argument.")
-        if not ( isinstance(self._max,(int,long)) or self._max is _MAXINF ):
-            raise TypeError("Invalid type of max argument.")
-        if ( self._min is not _MININF and self._max is not _MAXINF and
-             self._min > self._max ):
-            raise ValueError("Minimum is not smaller than maximum.")
-        if isinstance(self._max,(int,long)):
-            self._max += 1
-
-        # Process arguments.
-        for arg in args:
-            if isinstance(arg,(int,long)):
-                start, stop = arg, arg+1
-            elif isinstance(arg,tuple):
-                if len(arg) <> 2:
-                    raise ValueError("Invalid tuple, must be (start,stop).")
-
-                # Process argument.
-                start, stop = arg
-                if start is None:
-                    start = self._min
-                if stop is None:
-                    stop = self._max
-
-                # Check arguments.
-                if not ( isinstance(start,(int,long)) or start is _MININF ):
-                    raise TypeError("Invalid type of tuple start.")
-                if not ( isinstance(stop,(int,long)) or stop is _MAXINF ):
-                    raise TypeError("Invalid type of tuple stop.")
-                if ( start is not _MININF and stop is not _MAXINF and
-                     start > stop ):
-                    continue
-                if isinstance(stop,(int,long)):
-                    stop += 1
-            else:
-                raise TypeError("Invalid argument.")
-
-            if start > self._max:
-                continue
-            elif start < self._min:
-                start = self._min
-            if stop < self._min:
-                continue
-            elif stop > self._max:
-                stop = self._max
-            self._ranges.append((start,stop))
-
-        # Normalize set.
-        self._normalize()
-
-    # Utility functions for set operations
-    # ------------------------------------
-
-    def _iterranges(self,r1,r2,minval=_MININF,maxval=_MAXINF):
-        curval = minval
-        curstates = {"r1":False,"r2":False}
-        imax, jmax = 2*len(r1), 2*len(r2)
-        i, j = 0, 0
-        while i < imax or j < jmax:
-            if i < imax and ( ( j < jmax and
-                                r1[i>>1][i&1] < r2[j>>1][j&1] ) or
-                              j == jmax ):
-                cur_r, newname, newstate = r1[i>>1][i&1], "r1", not (i&1)
-                i += 1
-            else:
-                cur_r, newname, newstate = r2[j>>1][j&1], "r2", not (j&1)
-                j += 1
-            if curval < cur_r:
-                if cur_r > maxval:
-                    break
-                yield curstates, (curval,cur_r)
-                curval = cur_r
-            curstates[newname] = newstate
-        if curval < maxval:
-            yield curstates, (curval,maxval)
-
-    def _normalize(self):
-        self._ranges.sort()
-        i = 1
-        while i < len(self._ranges):
-            if self._ranges[i][0] < self._ranges[i-1][1]:
-                self._ranges[i-1] = (self._ranges[i-1][0],
-                                     max(self._ranges[i-1][1],
-                                         self._ranges[i][1]))
-                del self._ranges[i]
-            else:
-                i += 1
-        self._ranges = tuple(self._ranges)
-        self._hash = hash(self._ranges)
-
-    def __coerce__(self,other):
-        if isinstance(other,IntSet):
-            return self, other
-        elif isinstance(other,(int,long,tuple)):
-            try:
-                return self, self.__class__(other)
-            except TypeError:
-                # Catch a type error, in that case the structure specified by
-                # other is something we can't coerce, return NotImplemented.
-                # ValueErrors are not caught, they signal that the data was
-                # invalid for the constructor. This is appropriate to signal
-                # as a ValueError to the caller.
-                return NotImplemented
-        elif isinstance(other,list):
-            try:
-                return self, self.__class__(*other)
-            except TypeError:
-                # See above.
-                return NotImplemented
-        return NotImplemented
-
-    # Set function definitions
-    # ------------------------
-
-    def _make_function(name,type,doc,pall,pany=None):
-        """Makes a function to match two ranges. Accepts two types: either
-        'set', which defines a function which returns a set with all ranges
-        matching pall (pany is ignored), or 'bool', which returns True if pall
-        matches for all ranges and pany matches for any one range. doc is the
-        dostring to give this function. pany may be none to ignore the any
-        match.
-
-        The predicates get a dict with two keys, 'r1', 'r2', which denote
-        whether the current range is present in range1 (self) and/or range2
-        (other) or none of the two, respectively."""
-
-        if type == "set":
-            def f(self,other):
-                coerced = self.__coerce__(other)
-                if coerced is NotImplemented:
-                    return NotImplemented
-                other = coerced[1]
-                newset = self.__class__.__new__(self.__class__)
-                newset._min = min(self._min,other._min)
-                newset._max = max(self._max,other._max)
-                newset._ranges = []
-                for states, (start,stop) in \
-                        self._iterranges(self._ranges,other._ranges,
-                                         newset._min,newset._max):
-                    if pall(states):
-                        if newset._ranges and newset._ranges[-1][1] == start:
-                            newset._ranges[-1] = (newset._ranges[-1][0],stop)
-                        else:
-                            newset._ranges.append((start,stop))
-                newset._ranges = tuple(newset._ranges)
-                newset._hash = hash(self._ranges)
-                return newset
-        elif type == "bool":
-            def f(self,other):
-                coerced = self.__coerce__(other)
-                if coerced is NotImplemented:
-                    return NotImplemented
-                other = coerced[1]
-                _min = min(self._min,other._min)
-                _max = max(self._max,other._max)
-                found = not pany
-                for states, (start,stop) in \
-                        self._iterranges(self._ranges,other._ranges,_min,_max):
-                    if not pall(states):
-                        return False
-                    found = found or pany(states)
-                return found
-        else:
-            raise ValueError("Invalid type of function to create.")
-        try:
-            f.func_name = name
-        except TypeError:
-            pass
-        f.func_doc = doc
-        return f
-
-    # Intersection.
-    __and__ = _make_function("__and__","set",
-                             "Intersection of two sets as a new set.",
-                             lambda s: s["r1"] and s["r2"])
-    __rand__ = _make_function("__rand__","set",
-                              "Intersection of two sets as a new set.",
-                              lambda s: s["r1"] and s["r2"])
-    intersection = _make_function("intersection","set",
-                                  "Intersection of two sets as a new set.",
-                                  lambda s: s["r1"] and s["r2"])
-
-    # Union.
-    __or__ = _make_function("__or__","set",
-                            "Union of two sets as a new set.",
-                            lambda s: s["r1"] or s["r2"])
-    __ror__ = _make_function("__ror__","set",
-                             "Union of two sets as a new set.",
-                             lambda s: s["r1"] or s["r2"])
-    union = _make_function("union","set",
-                           "Union of two sets as a new set.",
-                           lambda s: s["r1"] or s["r2"])
-
-    # Difference.
-    __sub__ = _make_function("__sub__","set",
-                             "Difference of two sets as a new set.",
-                             lambda s: s["r1"] and not s["r2"])
-    __rsub__ = _make_function("__rsub__","set",
-                              "Difference of two sets as a new set.",
-                              lambda s: s["r2"] and not s["r1"])
-    difference = _make_function("difference","set",
-                                "Difference of two sets as a new set.",
-                                lambda s: s["r1"] and not s["r2"])
-
-    # Symmetric difference.
-    __xor__ = _make_function("__xor__","set",
-                             "Symmetric difference of two sets as a new set.",
-                             lambda s: s["r1"] ^ s["r2"])
-    __rxor__ = _make_function("__rxor__","set",
-                              "Symmetric difference of two sets as a new set.",
-                              lambda s: s["r1"] ^ s["r2"])
-    symmetric_difference = _make_function("symmetric_difference","set",
-                                          "Symmetric difference of two sets as a new set.",
-                                          lambda s: s["r1"] ^ s["r2"])
-
-    # Containership testing.
-    __contains__ = _make_function("__contains__","bool",
-                                  "Returns true if self is superset of other.",
-                                  lambda s: s["r1"] or not s["r2"])
-    issubset = _make_function("issubset","bool",
-                              "Returns true if self is subset of other.",
-                              lambda s: s["r2"] or not s["r1"])
-    istruesubset = _make_function("istruesubset","bool",
-                                  "Returns true if self is true subset of other.",
-                                  lambda s: s["r2"] or not s["r1"],
-                                  lambda s: s["r2"] and not s["r1"])
-    issuperset = _make_function("issuperset","bool",
-                                "Returns true if self is superset of other.",
-                                lambda s: s["r1"] or not s["r2"])
-    istruesuperset = _make_function("istruesuperset","bool",
-                                    "Returns true if self is true superset of other.",
-                                    lambda s: s["r1"] or not s["r2"],
-                                    lambda s: s["r1"] and not s["r2"])
-    overlaps = _make_function("overlaps","bool",
-                              "Returns true if self overlaps with other.",
-                              lambda s: True,
-                              lambda s: s["r1"] and s["r2"])
-
-    # Comparison.
-    __eq__ = _make_function("__eq__","bool",
-                            "Returns true if self is equal to other.",
-                            lambda s: not ( s["r1"] ^ s["r2"] ))
-    __ne__ = _make_function("__ne__","bool",
-                            "Returns true if self is different to other.",
-                            lambda s: True,
-                            lambda s: s["r1"] ^ s["r2"])
-
-    # Clean up namespace.
-    del _make_function
-
-    # Define other functions.
-    def inverse(self):
-        """Inverse of set as a new set."""
-
-        newset = self.__class__.__new__(self.__class__)
-        newset._min = self._min
-        newset._max = self._max
-        newset._ranges = []
-        laststop = self._min
-        for r in self._ranges:
-            if laststop < r[0]:
-                newset._ranges.append((laststop,r[0]))
-                laststop = r[1]
-        if laststop < self._max:
-            newset._ranges.append((laststop,self._max))
-        return newset
-
-    __invert__ = inverse
-
-    # Hashing
-    # -------
-
-    def __hash__(self):
-        """Returns a hash value representing this integer set. As the set is
-        always stored normalized, the hash value is guaranteed to match for
-        matching ranges."""
-
-        return self._hash
-
-    # Iterating
-    # ---------
-
-    def __len__(self):
-        """Get length of this integer set. In case the length is larger than
-        2**31 (including infinitely sized integer sets), it raises an
-        OverflowError. This is due to len() restricting the size to
-        0 <= len < 2**31."""
-
-        if not self._ranges:
-            return 0
-        if self._ranges[0][0] is _MININF or self._ranges[-1][1] is _MAXINF:
-            raise OverflowError("Infinitely sized integer set.")
-        rlen = 0
-        for r in self._ranges:
-            rlen += r[1]-r[0]
-        if rlen >= 2**31:
-            raise OverflowError("Integer set bigger than 2**31.")
-        return rlen
-
-    def len(self):
-        """Returns the length of this integer set as an integer. In case the
-        length is infinite, returns -1. This function exists because of a
-        limitation of the builtin len() function which expects values in
-        the range 0 <= len < 2**31. Use this function in case your integer
-        set might be larger."""
-
-        if not self._ranges:
-            return 0
-        if self._ranges[0][0] is _MININF or self._ranges[-1][1] is _MAXINF:
-            return -1
-        rlen = 0
-        for r in self._ranges:
-            rlen += r[1]-r[0]
-        return rlen
-
-    def __nonzero__(self):
-        """Returns true if this integer set contains at least one item."""
-
-        return bool(self._ranges)
-
-    def __iter__(self):
-        """Iterate over all values in this integer set. Iteration always starts
-        by iterating from lowest to highest over the ranges that are bounded.
-        After processing these, all ranges that are unbounded (maximum 2) are
-        yielded intermixed."""
-
-        ubranges = []
-        for r in self._ranges:
-            if r[0] is _MININF:
-                if r[1] is _MAXINF:
-                    ubranges.extend(([0,1],[-1,-1]))
-                else:
-                    ubranges.append([r[1]-1,-1])
-            elif r[1] is _MAXINF:
-                ubranges.append([r[0],1])
-            else:
-                for val in xrange(r[0],r[1]):
-                    yield val
-        if ubranges:
-            while True:
-                for ubrange in ubranges:
-                    yield ubrange[0]
-                    ubrange[0] += ubrange[1]
-
-    # Printing
-    # --------
-
-    def __repr__(self):
-        """Return a representation of this integer set. The representation is
-        executable to get an equal integer set."""
-
-        rv = []
-        for start, stop in self._ranges:
-            if ( isinstance(start,(int,long)) and isinstance(stop,(int,long))
-                 and stop-start == 1 ):
-                rv.append("%r" % start)
-            elif isinstance(stop,(int,long)):
-                rv.append("(%r,%r)" % (start,stop-1))
-            else:
-                rv.append("(%r,%r)" % (start,stop))
-        if self._min is not _MININF:
-            rv.append("min=%r" % self._min)
-        if self._max is not _MAXINF:
-            rv.append("max=%r" % self._max)
-        return "%s(%s)" % (self.__class__.__name__,",".join(rv))
-
-if __name__ == "__main__":
-    # Little test script demonstrating functionality.
-    x = IntSet((10,20),30)
-    y = IntSet((10,20))
-    z = IntSet((10,20),30,(15,19),min=0,max=40)
-    print x
-    print x&110
-    print x|110
-    print x^(15,25)
-    print x-12
-    print 12 in x
-    print x.issubset(x)
-    print y.issubset(x)
-    print x.istruesubset(x)
-    print y.istruesubset(x)
-    for val in x:
-        print val
-    print x.inverse()
-    print x == z
-    print x == y
-    print x <> y
-    print hash(x)
-    print hash(z)
-    print len(x)
-    print x.len()
diff --git a/lib/paste/util/ip4.py b/lib/paste/util/ip4.py
@@ -1,273 +0,0 @@
-# -*- coding: iso-8859-15 -*-
-"""IP4 address range set implementation.
-
-Implements an IPv4-range type.
-
-Copyright (C) 2006, Heiko Wundram.
-Released under the MIT-license.
-"""
-
-# Version information
-# -------------------
-
-__author__ = "Heiko Wundram <me@modelnine.org>"
-__version__ = "0.2"
-__revision__ = "3"
-__date__ = "2006-01-20"
-
-
-# Imports
-# -------
-
-import intset
-import socket
-
-
-# IP4Range class
-# --------------
-
-class IP4Range(intset.IntSet):
-    """IP4 address range class with efficient storage of address ranges.
-    Supports all set operations."""
-
-    _MINIP4 = 0
-    _MAXIP4 = (1<<32) - 1
-    _UNITYTRANS = "".join([chr(n) for n in range(256)])
-    _IPREMOVE = "0123456789."
-
-    def __init__(self,*args):
-        """Initialize an ip4range class. The constructor accepts an unlimited
-        number of arguments that may either be tuples in the form (start,stop),
-        integers, longs or strings, where start and stop in a tuple may
-        also be of the form integer, long or string.
-
-        Passing an integer or long means passing an IPv4-address that's already
-        been converted to integer notation, whereas passing a string specifies
-        an address where this conversion still has to be done. A string
-        address may be in the following formats:
-
-        - 1.2.3.4    - a plain address, interpreted as a single address
-        - 1.2.3      - a set of addresses, interpreted as 1.2.3.0-1.2.3.255
-        - localhost  - hostname to look up, interpreted as single address
-        - 1.2.3<->5  - a set of addresses, interpreted as 1.2.3.0-1.2.5.255
-        - 1.2.0.0/16 - a set of addresses, interpreted as 1.2.0.0-1.2.255.255
-
-        Only the first three notations are valid if you use a string address in
-        a tuple, whereby notation 2 is interpreted as 1.2.3.0 if specified as
-        lower bound and 1.2.3.255 if specified as upper bound, not as a range
-        of addresses.
-
-        Specifying a range is done with the <-> operator. This is necessary
-        because '-' might be present in a hostname. '<->' shouldn't be, ever.
-        """
-
-        # Special case copy constructor.
-        if len(args) == 1 and isinstance(args[0],IP4Range):
-            super(IP4Range,self).__init__(args[0])
-            return
-
-        # Convert arguments to tuple syntax.
-        args = list(args)
-        for i in range(len(args)):
-            argval = args[i]
-            if isinstance(argval,str):
-                if "<->" in argval:
-                    # Type 4 address.
-                    args[i] = self._parseRange(*argval.split("<->",1))
-                    continue
-                elif "/" in argval:
-                    # Type 5 address.
-                    args[i] = self._parseMask(*argval.split("/",1))
-                else:
-                    # Type 1, 2 or 3.
-                    args[i] = self._parseAddrRange(argval)
-            elif isinstance(argval,tuple):
-                if len(tuple) <> 2:
-                    raise ValueError("Tuple is of invalid length.")
-                addr1, addr2 = argval
-                if isinstance(addr1,str):
-                    addr1 = self._parseAddrRange(addr1)[0]
-                elif not isinstance(addr1,(int,long)):
-                    raise TypeError("Invalid argument.")
-                if isinstance(addr2,str):
-                    addr2 = self._parseAddrRange(addr2)[1]
-                elif not isinstance(addr2,(int,long)):
-                    raise TypeError("Invalid argument.")
-                args[i] = (addr1,addr2)
-            elif not isinstance(argval,(int,long)):
-                raise TypeError("Invalid argument.")
-
-        # Initialize the integer set.
-        super(IP4Range,self).__init__(min=self._MINIP4,max=self._MAXIP4,*args)
-
-    # Parsing functions
-    # -----------------
-
-    def _parseRange(self,addr1,addr2):
-        naddr1, naddr1len = _parseAddr(addr1)
-        naddr2, naddr2len = _parseAddr(addr2)
-        if naddr2len < naddr1len:
-            naddr2 += naddr1&(((1<<((naddr1len-naddr2len)*8))-1)<<
-                              (naddr2len*8))
-            naddr2len = naddr1len
-        elif naddr2len > naddr1len:
-            raise ValueError("Range has more dots than address.")
-        naddr1 <<= (4-naddr1len)*8
-        naddr2 <<= (4-naddr2len)*8
-        naddr2 += (1<<((4-naddr2len)*8))-1
-        return (naddr1,naddr2)
-
-    def _parseMask(self,addr,mask):
-        naddr, naddrlen = _parseAddr(addr)
-        naddr <<= (4-naddrlen)*8
-        try:
-            if not mask:
-                masklen = 0
-            else:
-                masklen = int(mask)
-            if not 0 <= masklen <= 32:
-                raise ValueError
-        except ValueError:
-            try:
-                mask = _parseAddr(mask,False)
-            except ValueError:
-                raise ValueError("Mask isn't parseable.")
-            remaining = 0
-            masklen = 0
-            if not mask:
-                masklen = 0
-            else:
-                while not (mask&1):
-                    remaining += 1
-                while (mask&1):
-                    mask >>= 1
-                    masklen += 1
-                if remaining+masklen <> 32:
-                    raise ValueError("Mask isn't a proper host mask.")
-        naddr1 = naddr & (((1<<masklen)-1)<<(32-masklen))
-        naddr2 = naddr1 + (1<<(32-masklen)) - 1
-        return (naddr1,naddr2)
-
-    def _parseAddrRange(self,addr):
-        naddr, naddrlen = _parseAddr(addr)
-        naddr1 = naddr<<((4-naddrlen)*8)
-        naddr2 = ( (naddr<<((4-naddrlen)*8)) +
-                   (1<<((4-naddrlen)*8)) - 1 )
-        return (naddr1,naddr2)
-
-    # Utility functions
-    # -----------------
-
-    def _int2ip(self,num):
-        rv = []
-        for i in range(4):
-            rv.append(str(num&255))
-            num >>= 8
-        return ".".join(reversed(rv))
-
-    # Iterating
-    # ---------
-
-    def iteraddresses(self):
-        """Returns an iterator which iterates over ips in this iprange. An
-        IP is returned in string form (e.g. '1.2.3.4')."""
-
-        for v in super(IP4Range,self).__iter__():
-            yield self._int2ip(v)
-
-    def iterranges(self):
-        """Returns an iterator which iterates over ip-ip ranges which build
-        this iprange if combined. An ip-ip pair is returned in string form
-        (e.g. '1.2.3.4-2.3.4.5')."""
-
-        for r in self._ranges:
-            if r[1]-r[0] == 1:
-                yield self._int2ip(r[0])
-            else:
-                yield '%s-%s' % (self._int2ip(r[0]),self._int2ip(r[1]-1))
-
-    def itermasks(self):
-        """Returns an iterator which iterates over ip/mask pairs which build
-        this iprange if combined. An IP/Mask pair is returned in string form
-        (e.g. '1.2.3.0/24')."""
-
-        for r in self._ranges:
-            for v in self._itermasks(r):
-                yield v
-
-    def _itermasks(self,r):
-        ranges = [r]
-        while ranges:
-            cur = ranges.pop()
-            curmask = 0
-            while True:
-                curmasklen = 1<<(32-curmask)
-                start = (cur[0]+curmasklen-1)&(((1<<curmask)-1)<<(32-curmask))
-                if start >= cur[0] and start+curmasklen <= cur[1]:
-                    break
-                else:
-                    curmask += 1
-            yield "%s/%s" % (self._int2ip(start),curmask)
-            if cur[0] < start:
-                ranges.append((cur[0],start))
-            if cur[1] > start+curmasklen:
-                ranges.append((start+curmasklen,cur[1]))
-
-    __iter__ = iteraddresses
-
-    # Printing
-    # --------
-
-    def __repr__(self):
-        """Returns a string which can be used to reconstruct this iprange."""
-
-        rv = []
-        for start, stop in self._ranges:
-            if stop-start == 1:
-                rv.append("%r" % (self._int2ip(start),))
-            else:
-                rv.append("(%r,%r)" % (self._int2ip(start),
-                                       self._int2ip(stop-1)))
-        return "%s(%s)" % (self.__class__.__name__,",".join(rv))
-
-def _parseAddr(addr,lookup=True):
-    if lookup and addr.translate(IP4Range._UNITYTRANS, IP4Range._IPREMOVE):
-        try:
-            addr = socket.gethostbyname(addr)
-        except socket.error:
-            raise ValueError("Invalid Hostname as argument.")
-    naddr = 0
-    for naddrpos, part in enumerate(addr.split(".")):
-        if naddrpos >= 4:
-            raise ValueError("Address contains more than four parts.")
-        try:
-            if not part:
-                part = 0
-            else:
-                part = int(part)
-            if not 0 <= part < 256:
-                raise ValueError
-        except ValueError:
-            raise ValueError("Address part out of range.")
-        naddr <<= 8
-        naddr += part
-    return naddr, naddrpos+1
-
-def ip2int(addr, lookup=True):
-    return _parseAddr(addr, lookup=lookup)[0]
-
-if __name__ == "__main__":
-    # Little test script.
-    x = IP4Range("172.22.162.250/24")
-    y = IP4Range("172.22.162.250","172.22.163.250","172.22.163.253<->255")
-    print x
-    for val in x.itermasks():
-        print val
-    for val in y.itermasks():
-        print val
-    for val in (x|y).itermasks():
-        print val
-    for val in (x^y).iterranges():
-        print val
-    for val in x:
-        print val
diff --git a/lib/paste/util/killthread.py b/lib/paste/util/killthread.py
@@ -1,30 +0,0 @@
-"""
-Kill a thread, from http://sebulba.wikispaces.com/recipe+thread2
-"""
-import types
-try:
-    import ctypes
-except ImportError:
-    raise ImportError(
-        "You cannot use paste.util.killthread without ctypes installed")
-if not hasattr(ctypes, 'pythonapi'):
-    raise ImportError(
-        "You cannot use paste.util.killthread without ctypes.pythonapi")
-
-def async_raise(tid, exctype):
-    """raises the exception, performs cleanup if needed.
-
-    tid is the value given by thread.get_ident() (an integer).
-    Raise SystemExit to kill a thread."""
-    if not isinstance(exctype, (types.ClassType, type)):
-        raise TypeError("Only types can be raised (not instances)")
-    if not isinstance(tid, int):
-        raise TypeError("tid must be an integer")
-    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
-    if res == 0:
-        raise ValueError("invalid thread id")
-    elif res != 1:
-        # """if it returns a number greater than one, you're in trouble, 
-        # and you should call it again with exc=NULL to revert the effect"""
-        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, 0)
-        raise SystemError("PyThreadState_SetAsyncExc failed")
diff --git a/lib/paste/util/looper.py b/lib/paste/util/looper.py
@@ -1,152 +0,0 @@
-"""
-Helper for looping over sequences, particular in templates.
-
-Often in a loop in a template it's handy to know what's next up,
-previously up, if this is the first or last item in the sequence, etc.
-These can be awkward to manage in a normal Python loop, but using the
-looper you can get a better sense of the context.  Use like::
-
-    >>> for loop, item in looper(['a', 'b', 'c']):
-    ...     print loop.number, item
-    ...     if not loop.last:
-    ...         print '---'
-    1 a
-    ---
-    2 b
-    ---
-    3 c
-
-"""
-
-__all__ = ['looper']
-
-class looper(object):
-    """
-    Helper for looping (particularly in templates)
-    
-    Use this like::
-    
-        for loop, item in looper(seq):
-            if loop.first:
-                ...
-    """
-
-    def __init__(self, seq):
-        self.seq = seq
-
-    def __iter__(self):
-        return looper_iter(self.seq)
-
-    def __repr__(self):
-        return '<%s for %r>' % (
-            self.__class__.__name__, self.seq)
-
-class looper_iter(object):
-
-    def __init__(self, seq):
-        self.seq = list(seq)
-        self.pos = 0
-
-    def __iter__(self):
-        return self
-
-    def next(self):
-        if self.pos >= len(self.seq):
-            raise StopIteration
-        result = loop_pos(self.seq, self.pos), self.seq[self.pos]
-        self.pos += 1
-        return result
-
-class loop_pos(object):
-
-    def __init__(self, seq, pos):
-        self.seq = seq
-        self.pos = pos
-
-    def __repr__(self):
-        return '<loop pos=%r at %r>' % (
-            self.seq[pos], pos)
-
-    def index(self):
-        return self.pos
-    index = property(index)
-
-    def number(self):
-        return self.pos + 1
-    number = property(number)
-
-    def item(self):
-        return self.seq[self.pos]
-    item = property(item)
-
-    def next(self):
-        try:
-            return self.seq[self.pos+1]
-        except IndexError:
-            return None
-    next = property(next)
-
-    def previous(self):
-        if self.pos == 0:
-            return None
-        return self.seq[self.pos-1]
-    previous = property(previous)
-
-    def odd(self):
-        return not self.pos % 2
-    odd = property(odd)
-
-    def even(self):
-        return self.pos % 2
-    even = property(even)
-
-    def first(self):
-        return self.pos == 0
-    first = property(first)
-
-    def last(self):
-        return self.pos == len(self.seq)-1
-    last = property(last)
-
-    def length(self):
-        return len(self.seq)
-    length = property(length)
-
-    def first_group(self, getter=None):
-        """
-        Returns true if this item is the start of a new group,
-        where groups mean that some attribute has changed.  The getter
-        can be None (the item itself changes), an attribute name like
-        ``'.attr'``, a function, or a dict key or list index.
-        """
-        if self.first:
-            return True
-        return self._compare_group(self.item, self.previous, getter)
-
-    def last_group(self, getter=None):
-        """
-        Returns true if this item is the end of a new group,
-        where groups mean that some attribute has changed.  The getter
-        can be None (the item itself changes), an attribute name like
-        ``'.attr'``, a function, or a dict key or list index.
-        """
-        if self.last:
-            return True
-        return self._compare_group(self.item, self.next, getter)
-
-    def _compare_group(self, item, other, getter):
-        if getter is None:
-            return item != other
-        elif (isinstance(getter, basestring)
-              and getter.startswith('.')):
-            getter = getter[1:]
-            if getter.endswith('()'):
-                getter = getter[:-2]
-                return getattr(item, getter)() != getattr(other, getter)()
-            else:
-                return getattr(item, getter) != getattr(other, getter)
-        elif callable(getter):
-            return getter(item) != getter(other)
-        else:
-            return item[getter] != other[getter]
-    
diff --git a/lib/paste/util/mimeparse.py b/lib/paste/util/mimeparse.py
@@ -1,178 +0,0 @@
-"""MIME-Type Parser
-
-This module provides basic functions for handling mime-types. It can handle
-matching mime-types against a list of media-ranges. See section 14.1 of 
-the HTTP specification [RFC 2616] for a complete explaination.
-
-   http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
-
-Contents:
-    - parse_mime_type():   Parses a mime-type into it's component parts.
-    - parse_media_range(): Media-ranges are mime-types with wild-cards and a 'q' quality parameter.
-    - quality():           Determines the quality ('q') of a mime-type when compared against a list of media-ranges.
-    - quality_parsed():    Just like quality() except the second parameter must be pre-parsed.
-    - best_match():        Choose the mime-type with the highest quality ('q') from a list of candidates. 
-    - desired_matches():   Provide a list in order of server-desired priorities from a list of candidates.
-"""
-
-__version__ = "0.1.1"
-__author__ = 'Joe Gregorio'
-__email__ = "joe@bitworking.org"
-__credits__ = ""
-
-def parse_mime_type(mime_type):
-    """Carves up a mime_type and returns a tuple of the
-       (type, subtype, params) where 'params' is a dictionary
-       of all the parameters for the media range.
-       For example, the media range 'application/xhtml;q=0.5' would
-       get parsed into:
-
-       ('application', 'xhtml', {'q', '0.5'})
-       """
-    parts = mime_type.split(";")
-    params = dict([tuple([s.strip() for s in param.split("=")])\
-            for param in parts[1:] ])
-    (type, subtype) = parts[0].split("/")
-    return (type.strip(), subtype.strip(), params)
-
-def parse_media_range(range):
-    """Carves up a media range and returns a tuple of the
-       (type, subtype, params) where 'params' is a dictionary
-       of all the parameters for the media range.
-       
-       For example, the media range ``application/*;q=0.5`` would
-       get parsed into::
-
-         ('application', '*', {'q', '0.5'})
-
-       In addition this function also guarantees that there 
-       is a value for 'q' in the params dictionary, filling it
-       in with a proper default if necessary.
-       """
-    (type, subtype, params) = parse_mime_type(range)
-    if not params.has_key('q') or not params['q'] or \
-            not float(params['q']) or float(params['q']) > 1\
-            or float(params['q']) < 0:
-        params['q'] = '1'
-    return (type, subtype, params)
-
-def quality_parsed(mime_type, parsed_ranges):
-    """Find the best match for a given mime_type against 
-       a list of media_ranges that have already been 
-       parsed by parse_media_range(). Returns the 
-       'q' quality parameter of the best match, 0 if no
-       match was found. This function bahaves the same as quality()
-       except that 'parsed_ranges' must be a list of
-       parsed media ranges. """
-    best_fitness = -1 
-    best_match = ""
-    best_fit_q = 0
-    (target_type, target_subtype, target_params) =\
-            parse_media_range(mime_type)
-    for (type, subtype, params) in parsed_ranges:
-        param_matches = sum([1 for (key, value) in \
-                target_params.iteritems() if key != 'q' and \
-                params.has_key(key) and value == params[key]])
-        if (type == target_type or type == '*') and \
-                (subtype == target_subtype or subtype == "*"):
-            fitness = (type == target_type) and 100 or 0
-            fitness += (subtype == target_subtype) and 10 or 0
-            fitness += param_matches
-            if fitness > best_fitness:
-                best_fitness = fitness
-                best_fit_q = params['q']
-            
-    return float(best_fit_q)
-    
-def quality(mime_type, ranges):
-    """Returns the quality 'q' of a mime_type when compared
-    against the media-ranges in ranges. For example:
-
-    >>> quality('text/html','text/*;q=0.3, text/html;q=0.7, text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5')
-    0.7
-    
-    """ 
-    parsed_ranges = [parse_media_range(r) for r in ranges.split(",")]
-    return quality_parsed(mime_type, parsed_ranges)
-
-def best_match(supported, header):
-    """Takes a list of supported mime-types and finds the best
-    match for all the media-ranges listed in header. The value of
-    header must be a string that conforms to the format of the 
-    HTTP Accept: header. The value of 'supported' is a list of
-    mime-types.
-    
-    >>> best_match(['application/xbel+xml', 'text/xml'], 'text/*;q=0.5,*/*; q=0.1')
-    'text/xml'
-    """
-    parsed_header = [parse_media_range(r) for r in header.split(",")]
-    weighted_matches = [(quality_parsed(mime_type, parsed_header), mime_type)\
-            for mime_type in supported]
-    weighted_matches.sort()
-    return weighted_matches[-1][0] and weighted_matches[-1][1] or ''
-
-def desired_matches(desired, header):
-    """Takes a list of desired mime-types in the order the server prefers to
-    send them regardless of the browsers preference.
-    
-    Browsers (such as Firefox) technically want XML over HTML depending on how
-    one reads the specification. This function is provided for a server to 
-    declare a set of desired mime-types it supports, and returns a subset of 
-    the desired list in the same order should each one be Accepted by the
-    browser.
-    
-    >>> sorted_match(['text/html', 'application/xml'], \
-    ...     'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png')
-    ['text/html', 'application/xml']
-    >>> sorted_match(['text/html', 'application/xml'], 'application/xml,application/json')
-    ['application/xml']
-    """
-    matches = []
-    parsed_ranges = [parse_media_range(r) for r in header.split(",")]
-    for mimetype in desired:
-        if quality_parsed(mimetype, parsed_ranges):
-            matches.append(mimetype)
-    return matches
-
-if __name__ == "__main__":
-    import unittest
-
-    class TestMimeParsing(unittest.TestCase):
-
-        def test_parse_media_range(self):
-            self.assert_(('application', 'xml', {'q': '1'}) == parse_media_range('application/xml;q=1'))
-            self.assertEqual(('application', 'xml', {'q': '1'}), parse_media_range('application/xml'))
-            self.assertEqual(('application', 'xml', {'q': '1'}), parse_media_range('application/xml;q='))
-            self.assertEqual(('application', 'xml', {'q': '1'}), parse_media_range('application/xml ; q='))
-            self.assertEqual(('application', 'xml', {'q': '1', 'b': 'other'}), parse_media_range('application/xml ; q=1;b=other'))
-            self.assertEqual(('application', 'xml', {'q': '1', 'b': 'other'}), parse_media_range('application/xml ; q=2;b=other'))
-
-        def test_rfc_2616_example(self):
-            accept = "text/*;q=0.3, text/html;q=0.7, text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5"
-            self.assertEqual(1, quality("text/html;level=1", accept))
-            self.assertEqual(0.7, quality("text/html", accept))
-            self.assertEqual(0.3, quality("text/plain", accept))
-            self.assertEqual(0.5, quality("image/jpeg", accept))
-            self.assertEqual(0.4, quality("text/html;level=2", accept))
-            self.assertEqual(0.7, quality("text/html;level=3", accept))
-
-        def test_best_match(self):
-            mime_types_supported = ['application/xbel+xml', 'application/xml']
-            # direct match
-            self.assertEqual(best_match(mime_types_supported, 'application/xbel+xml'), 'application/xbel+xml')
-            # direct match with a q parameter
-            self.assertEqual(best_match(mime_types_supported, 'application/xbel+xml; q=1'), 'application/xbel+xml')
-            # direct match of our second choice with a q parameter
-            self.assertEqual(best_match(mime_types_supported, 'application/xml; q=1'), 'application/xml')
-            # match using a subtype wildcard
-            self.assertEqual(best_match(mime_types_supported, 'application/*; q=1'), 'application/xml')
-            # match using a type wildcard
-            self.assertEqual(best_match(mime_types_supported, '*/*'), 'application/xml')
-
-            mime_types_supported = ['application/xbel+xml', 'text/xml']
-            # match using a type versus a lower weighted subtype
-            self.assertEqual(best_match(mime_types_supported, 'text/*;q=0.5,*/*; q=0.1'), 'text/xml')
-            # fail to match anything
-            self.assertEqual(best_match(mime_types_supported, 'text/html,application/atom+xml; q=0.9'), '')
-
-    unittest.main() 
diff --git a/lib/paste/util/multidict.py b/lib/paste/util/multidict.py
@@ -1,397 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-import cgi
-import copy
-import sys
-from UserDict import DictMixin
-
-class MultiDict(DictMixin):
-
-    """
-    An ordered dictionary that can have multiple values for each key.
-    Adds the methods getall, getone, mixed, and add to the normal
-    dictionary interface.
-    """
-
-    def __init__(self, *args, **kw):
-        if len(args) > 1:
-            raise TypeError(
-                "MultiDict can only be called with one positional argument")
-        if args:
-            if hasattr(args[0], 'iteritems'):
-                items = list(args[0].iteritems())
-            elif hasattr(args[0], 'items'):
-                items = args[0].items()
-            else:
-                items = list(args[0])
-            self._items = items
-        else:
-            self._items = []
-        self._items.extend(kw.iteritems())
-
-    def __getitem__(self, key):
-        for k, v in self._items:
-            if k == key:
-                return v
-        raise KeyError(repr(key))
-
-    def __setitem__(self, key, value):
-        try:
-            del self[key]
-        except KeyError:
-            pass
-        self._items.append((key, value))
-
-    def add(self, key, value):
-        """
-        Add the key and value, not overwriting any previous value.
-        """
-        self._items.append((key, value))
-
-    def getall(self, key):
-        """
-        Return a list of all values matching the key (may be an empty list)
-        """
-        result = []
-        for k, v in self._items:
-            if key == k:
-                result.append(v)
-        return result
-
-    def getone(self, key):
-        """
-        Get one value matching the key, raising a KeyError if multiple
-        values were found.
-        """
-        v = self.getall(key)
-        if not v:
-            raise KeyError('Key not found: %r' % key)
-        if len(v) > 1:
-            raise KeyError('Multiple values match %r: %r' % (key, v))
-        return v[0]
-
-    def mixed(self):
-        """
-        Returns a dictionary where the values are either single
-        values, or a list of values when a key/value appears more than
-        once in this dictionary.  This is similar to the kind of
-        dictionary often used to represent the variables in a web
-        request.
-        """
-        result = {}
-        multi = {}
-        for key, value in self._items:
-            if key in result:
-                # We do this to not clobber any lists that are
-                # *actual* values in this dictionary:
-                if key in multi:
-                    result[key].append(value)
-                else:
-                    result[key] = [result[key], value]
-                    multi[key] = None
-            else:
-                result[key] = value
-        return result
-
-    def dict_of_lists(self):
-        """
-        Returns a dictionary where each key is associated with a
-        list of values.
-        """
-        result = {}
-        for key, value in self._items:
-            if key in result:
-                result[key].append(value)
-            else:
-                result[key] = [value]
-        return result
-
-    def __delitem__(self, key):
-        items = self._items
-        found = False
-        for i in range(len(items)-1, -1, -1):
-            if items[i][0] == key:
-                del items[i]
-                found = True
-        if not found:
-            raise KeyError(repr(key))
-
-    def __contains__(self, key):
-        for k, v in self._items:
-            if k == key:
-                return True
-        return False
-
-    has_key = __contains__
-
-    def clear(self):
-        self._items = []
-
-    def copy(self):
-        return MultiDict(self)
-
-    def setdefault(self, key, default=None):
-        for k, v in self._items:
-            if key == k:
-                return v
-        self._items.append((key, default))
-        return default
-
-    def pop(self, key, *args):
-        if len(args) > 1:
-            raise TypeError, "pop expected at most 2 arguments, got "\
-                              + repr(1 + len(args))
-        for i in range(len(self._items)):
-            if self._items[i][0] == key:
-                v = self._items[i][1]
-                del self._items[i]
-                return v
-        if args:
-            return args[0]
-        else:
-            raise KeyError(repr(key))
-
-    def popitem(self):
-        return self._items.pop()
-
-    def update(self, other=None, **kwargs):
-        if other is None:
-            pass
-        elif hasattr(other, 'items'):
-            self._items.extend(other.items())
-        elif hasattr(other, 'keys'):
-            for k in other.keys():
-                self._items.append((k, other[k]))
-        else:
-            for k, v in other:
-                self._items.append((k, v))
-        if kwargs:
-            self.update(kwargs)
-
-    def __repr__(self):
-        items = ', '.join(['(%r, %r)' % v for v in self._items])
-        return '%s([%s])' % (self.__class__.__name__, items)
-
-    def __len__(self):
-        return len(self._items)
-
-    ##
-    ## All the iteration:
-    ##
-
-    def keys(self):
-        return [k for k, v in self._items]
-
-    def iterkeys(self):
-        for k, v in self._items:
-            yield k
-
-    __iter__ = iterkeys
-
-    def items(self):
-        return self._items[:]
-
-    def iteritems(self):
-        return iter(self._items)
-
-    def values(self):
-        return [v for k, v in self._items]
-
-    def itervalues(self):
-        for k, v in self._items:
-            yield v
-
-class UnicodeMultiDict(DictMixin):
-    """
-    A MultiDict wrapper that decodes returned values to unicode on the
-    fly. Decoding is not applied to assigned values.
-
-    The key/value contents are assumed to be ``str``/``strs`` or
-    ``str``/``FieldStorages`` (as is returned by the ``paste.request.parse_``
-    functions).
-
-    Can optionally also decode keys when the ``decode_keys`` argument is
-    True.
-
-    ``FieldStorage`` instances are cloned, and the clone's ``filename``
-    variable is decoded. Its ``name`` variable is decoded when ``decode_keys``
-    is enabled.
-
-    """
-    def __init__(self, multi=None, encoding=None, errors='strict',
-                 decode_keys=False):
-        self.multi = multi
-        if encoding is None:
-            encoding = sys.getdefaultencoding()
-        self.encoding = encoding
-        self.errors = errors
-        self.decode_keys = decode_keys
-
-    def _decode_key(self, key):
-        if self.decode_keys:
-            try:
-                key = key.decode(self.encoding, self.errors)
-            except AttributeError:
-                pass
-        return key
-
-    def _decode_value(self, value):
-        """
-        Decode the specified value to unicode. Assumes value is a ``str`` or
-        `FieldStorage`` object.
-
-        ``FieldStorage`` objects are specially handled.
-        """
-        if isinstance(value, cgi.FieldStorage):
-            # decode FieldStorage's field name and filename
-            value = copy.copy(value)
-            if self.decode_keys:
-                value.name = value.name.decode(self.encoding, self.errors)
-            value.filename = value.filename.decode(self.encoding, self.errors)
-        else:
-            try:
-                value = value.decode(self.encoding, self.errors)
-            except AttributeError:
-                pass
-        return value
-
-    def __getitem__(self, key):
-        return self._decode_value(self.multi.__getitem__(key))
-
-    def __setitem__(self, key, value):
-        self.multi.__setitem__(key, value)
-
-    def add(self, key, value):
-        """
-        Add the key and value, not overwriting any previous value.
-        """
-        self.multi.add(key, value)
-
-    def getall(self, key):
-        """
-        Return a list of all values matching the key (may be an empty list)
-        """
-        return [self._decode_value(v) for v in self.multi.getall(key)]
-
-    def getone(self, key):
-        """
-        Get one value matching the key, raising a KeyError if multiple
-        values were found.
-        """
-        return self._decode_value(self.multi.getone(key))
-
-    def mixed(self):
-        """
-        Returns a dictionary where the values are either single
-        values, or a list of values when a key/value appears more than
-        once in this dictionary.  This is similar to the kind of
-        dictionary often used to represent the variables in a web
-        request.
-        """
-        unicode_mixed = {}
-        for key, value in self.multi.mixed().iteritems():
-            if isinstance(value, list):
-                value = [self._decode_value(value) for value in value]
-            else:
-                value = self._decode_value(value)
-            unicode_mixed[self._decode_key(key)] = value
-        return unicode_mixed
-
-    def dict_of_lists(self):
-        """
-        Returns a dictionary where each key is associated with a
-        list of values.
-        """
-        unicode_dict = {}
-        for key, value in self.multi.dict_of_lists().iteritems():
-            value = [self._decode_value(value) for value in value]
-            unicode_dict[self._decode_key(key)] = value
-        return unicode_dict
-
-    def __delitem__(self, key):
-        self.multi.__delitem__(key)
-
-    def __contains__(self, key):
-        return self.multi.__contains__(key)
-
-    has_key = __contains__
-
-    def clear(self):
-        self.multi.clear()
-
-    def copy(self):
-        return UnicodeMultiDict(self.multi.copy(), self.encoding, self.errors)
-
-    def setdefault(self, key, default=None):
-        return self._decode_value(self.multi.setdefault(key, default))
-
-    def pop(self, key, *args):
-        return self._decode_value(self.multi.pop(key, *args))
-
-    def popitem(self):
-        k, v = self.multi.popitem()
-        return (self._decode_key(k), self._decode_value(v))
-
-    def __repr__(self):
-        items = ', '.join(['(%r, %r)' % v for v in self.items()])
-        return '%s([%s])' % (self.__class__.__name__, items)
-
-    def __len__(self):
-        return self.multi.__len__()
-
-    ##
-    ## All the iteration:
-    ##
-
-    def keys(self):
-        return [self._decode_key(k) for k in self.multi.iterkeys()]
-
-    def iterkeys(self):
-        for k in self.multi.iterkeys():
-            yield self._decode_key(k)
-
-    __iter__ = iterkeys
-
-    def items(self):
-        return [(self._decode_key(k), self._decode_value(v)) for \
-                    k, v in self.multi.iteritems()]
-
-    def iteritems(self):
-        for k, v in self.multi.iteritems():
-            yield (self._decode_key(k), self._decode_value(v))
-
-    def values(self):
-        return [self._decode_value(v) for v in self.multi.itervalues()]
-
-    def itervalues(self):
-        for v in self.multi.itervalues():
-            yield self._decode_value(v)
-
-__test__ = {
-    'general': """
-    >>> d = MultiDict(a=1, b=2)
-    >>> d['a']
-    1
-    >>> d.getall('c')
-    []
-    >>> d.add('a', 2)
-    >>> d['a']
-    1
-    >>> d.getall('a')
-    [1, 2]
-    >>> d['b'] = 4
-    >>> d.getall('b')
-    [4]
-    >>> d.keys()
-    ['a', 'a', 'b']
-    >>> d.items()
-    [('a', 1), ('a', 2), ('b', 4)]
-    >>> d.mixed()
-    {'a': [1, 2], 'b': 4}
-    >>> MultiDict([('a', 'b')], c=2)
-    MultiDict([('a', 'b'), ('c', 2)])
-    """}
-
-if __name__ == '__main__':
-    import doctest
-    doctest.testmod()
diff --git a/lib/paste/util/quoting.py b/lib/paste/util/quoting.py
@@ -1,80 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-import cgi
-import htmlentitydefs
-import urllib
-import re
-
-__all__ = ['html_quote', 'html_unquote', 'url_quote', 'url_unquote',
-           'strip_html']
-
-default_encoding = 'UTF-8'
-
-def html_quote(v, encoding=None):
-    r"""
-    Quote the value (turned to a string) as HTML.  This quotes <, >,
-    and quotes:
-
-    >>> html_quote(1)
-    '1'
-    >>> html_quote(None)
-    ''
-    >>> html_quote('<hey!>')
-    '&lt;hey!&gt;'
-    >>> html_quote(u'\u1029')
-    '\xe1\x80\xa9'
-    """
-    encoding = encoding or default_encoding
-    if v is None:
-        return ''
-    elif isinstance(v, str):
-        return cgi.escape(v, 1)
-    elif isinstance(v, unicode):
-        return cgi.escape(v.encode(encoding), 1)
-    else:
-        return cgi.escape(unicode(v).encode(encoding), 1)
-
-_unquote_re = re.compile(r'&([a-zA-Z]+);')
-def _entity_subber(match, name2c=htmlentitydefs.name2codepoint):
-    code = name2c.get(match.group(1))
-    if code:
-        return unichr(code)
-    else:
-        return match.group(0)
-
-def html_unquote(s, encoding=None):
-    r"""
-    Decode the value.
-
-    >>> html_unquote('&lt;hey&nbsp;you&gt;')
-    u'<hey\xa0you>'
-    >>> html_unquote('')
-    u''
-    >>> html_unquote('&blahblah;')
-    u'&blahblah;'
-    >>> html_unquote('\xe1\x80\xa9')
-    u'\u1029'
-    """
-    if isinstance(s, str):
-        s = s.decode(encoding or default_encoding)
-    return _unquote_re.sub(_entity_subber, s)
-
-def strip_html(s):
-    # should this use html_unquote?
-    s = re.sub('<.*?>', '', s)
-    s = html_unquote(s)
-    return s
-
-def no_quote(s):
-    """
-    Quoting that doesn't do anything
-    """
-    return s
-
-url_quote = urllib.quote
-url_unquote = urllib.unquote
-
-if __name__ == '__main__':
-    import doctest
-    doctest.testmod()
diff --git a/lib/paste/util/scgiserver.py b/lib/paste/util/scgiserver.py
@@ -1,172 +0,0 @@
-#! /usr/bin/env python
-"""
-SCGI-->WSGI application proxy, "SWAP".
-
-(Originally written by Titus Brown.)
-
-This lets an SCGI front-end like mod_scgi be used to execute WSGI
-application objects.  To use it, subclass the SWAP class like so::
-
-   class TestAppHandler(swap.SWAP):
-       def __init__(self, *args, **kwargs):
-           self.prefix = '/canal'
-           self.app_obj = TestAppClass
-           swap.SWAP.__init__(self, *args, **kwargs)
-
-where 'TestAppClass' is the application object from WSGI and '/canal'
-is the prefix for what is served by the SCGI Web-server-side process.
-
-Then execute the SCGI handler "as usual" by doing something like this::
-
-   scgi_server.SCGIServer(TestAppHandler, port=4000).serve()
-
-and point mod_scgi (or whatever your SCGI front end is) at port 4000.
-
-Kudos to the WSGI folk for writing a nice PEP & the Quixote folk for
-writing a nice extensible SCGI server for Python!
-"""
-
-import sys
-import time
-from scgi import scgi_server
-
-def debug(msg):
-    timestamp = time.strftime("%Y-%m-%d %H:%M:%S",
-                              time.localtime(time.time()))
-    sys.stderr.write("[%s] %s\n" % (timestamp, msg))
-
-class SWAP(scgi_server.SCGIHandler):
-    """
-    SCGI->WSGI application proxy: let an SCGI server execute WSGI
-    application objects.
-    """
-    app_obj = None
-    prefix = None
-    
-    def __init__(self, *args, **kwargs):
-        assert self.app_obj, "must set app_obj"
-        assert self.prefix is not None, "must set prefix"
-        args = (self,) + args
-        scgi_server.SCGIHandler.__init__(*args, **kwargs)
-
-    def handle_connection(self, conn):
-        """
-        Handle an individual connection.
-        """
-        input = conn.makefile("r")
-        output = conn.makefile("w")
-
-        environ = self.read_env(input)
-        environ['wsgi.input']        = input
-        environ['wsgi.errors']       = sys.stderr
-        environ['wsgi.version']      = (1, 0)
-        environ['wsgi.multithread']  = False
-        environ['wsgi.multiprocess'] = True
-        environ['wsgi.run_once']     = False
-
-        # dunno how SCGI does HTTPS signalling; can't test it myself... @CTB
-        if environ.get('HTTPS','off') in ('on','1'):
-            environ['wsgi.url_scheme'] = 'https'
-        else:
-            environ['wsgi.url_scheme'] = 'http'
-
-        ## SCGI does some weird environ manglement.  We need to set
-        ## SCRIPT_NAME from 'prefix' and then set PATH_INFO from
-        ## REQUEST_URI.
-
-        prefix = self.prefix
-        path = environ['REQUEST_URI'][len(prefix):].split('?', 1)[0]
-
-        environ['SCRIPT_NAME'] = prefix
-        environ['PATH_INFO'] = path
-
-        headers_set = []
-        headers_sent = []
-        chunks = []
-        def write(data):
-            chunks.append(data)
-        
-        def start_response(status, response_headers, exc_info=None):
-            if exc_info:
-                try:
-                    if headers_sent:
-                        # Re-raise original exception if headers sent
-                        raise exc_info[0], exc_info[1], exc_info[2]
-                finally:
-                    exc_info = None     # avoid dangling circular ref
-            elif headers_set:
-                raise AssertionError("Headers already set!")
-
-            headers_set[:] = [status, response_headers]
-            return write
-
-        ###
-
-        result = self.app_obj(environ, start_response)
-        try:
-            for data in result:
-                chunks.append(data)
-                
-            # Before the first output, send the stored headers
-            if not headers_set:
-                # Error -- the app never called start_response
-                status = '500 Server Error'
-                response_headers = [('Content-type', 'text/html')]
-                chunks = ["XXX start_response never called"]
-            else:
-                status, response_headers = headers_sent[:] = headers_set
-                
-            output.write('Status: %s\r\n' % status)
-            for header in response_headers:
-                output.write('%s: %s\r\n' % header)
-            output.write('\r\n')
-
-            for data in chunks:
-                output.write(data)
-        finally:
-            if hasattr(result,'close'):
-                result.close()
-
-        # SCGI backends use connection closing to signal 'fini'.
-        try:
-            input.close()
-            output.close()
-            conn.close()
-        except IOError, err:
-            debug("IOError while closing connection ignored: %s" % err)
-
-
-def serve_application(application, prefix, port=None, host=None, max_children=None):
-    """
-    Serve the specified WSGI application via SCGI proxy.
-
-    ``application``
-        The WSGI application to serve.
-
-    ``prefix``
-        The prefix for what is served by the SCGI Web-server-side process.
-
-    ``port``
-        Optional port to bind the SCGI proxy to. Defaults to SCGIServer's
-        default port value.
-
-    ``host``
-        Optional host to bind the SCGI proxy to. Defaults to SCGIServer's
-        default host value.
-
-    ``host``
-        Optional maximum number of child processes the SCGIServer will
-        spawn. Defaults to SCGIServer's default max_children value.
-    """
-    class SCGIAppHandler(SWAP):
-        def __init__ (self, *args, **kwargs):
-            self.prefix = prefix
-            self.app_obj = application
-            SWAP.__init__(self, *args, **kwargs)
-
-    kwargs = dict(handler_class=SCGIAppHandler)
-    for kwarg in ('host', 'port', 'max_children'):
-        if locals()[kwarg] is not None:
-            kwargs[kwarg] = locals()[kwarg]
-
-    scgi_server.SCGIServer(**kwargs).serve()
diff --git a/lib/paste/util/string24.py b/lib/paste/util/string24.py
@@ -1,531 +0,0 @@
-"""A collection of string operations (most are no longer used).
-
-Warning: most of the code you see here isn't normally used nowadays.
-Beginning with Python 1.6, many of these functions are implemented as
-methods on the standard string object. They used to be implemented by
-a built-in module called strop, but strop is now obsolete itself.
-
-Public module variables:
-
-whitespace -- a string containing all characters considered whitespace
-lowercase -- a string containing all characters considered lowercase letters
-uppercase -- a string containing all characters considered uppercase letters
-letters -- a string containing all characters considered letters
-digits -- a string containing all characters considered decimal digits
-hexdigits -- a string containing all characters considered hexadecimal digits
-octdigits -- a string containing all characters considered octal digits
-punctuation -- a string containing all characters considered punctuation
-printable -- a string containing all characters considered printable
-
-"""
-
-# Some strings for ctype-style character classification
-whitespace = ' \t\n\r\v\f'
-lowercase = 'abcdefghijklmnopqrstuvwxyz'
-uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-letters = lowercase + uppercase
-ascii_lowercase = lowercase
-ascii_uppercase = uppercase
-ascii_letters = ascii_lowercase + ascii_uppercase
-digits = '0123456789'
-hexdigits = digits + 'abcdef' + 'ABCDEF'
-octdigits = '01234567'
-punctuation = """!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"""
-printable = digits + letters + punctuation + whitespace
-
-# Case conversion helpers
-# Use str to convert Unicode literal in case of -U
-# Note that Cookie.py bogusly uses _idmap :(
-l = map(chr, xrange(256))
-_idmap = str('').join(l)
-del l
-
-# Functions which aren't available as string methods.
-
-# Capitalize the words in a string, e.g. " aBc  dEf " -> "Abc Def".
-# See also regsub.capwords().
-def capwords(s, sep=None):
-    """capwords(s, [sep]) -> string
-
-    Split the argument into words using split, capitalize each
-    word using capitalize, and join the capitalized words using
-    join. Note that this replaces runs of whitespace characters by
-    a single space.
-
-    """
-    return (sep or ' ').join([x.capitalize() for x in s.split(sep)])
-
-
-# Construct a translation string
-_idmapL = None
-def maketrans(fromstr, tostr):
-    """maketrans(frm, to) -> string
-
-    Return a translation table (a string of 256 bytes long)
-    suitable for use in string.translate.  The strings frm and to
-    must be of the same length.
-
-    """
-    if len(fromstr) != len(tostr):
-        raise ValueError, "maketrans arguments must have same length"
-    global _idmapL
-    if not _idmapL:
-        _idmapL = map(None, _idmap)
-    L = _idmapL[:]
-    fromstr = map(ord, fromstr)
-    for i in range(len(fromstr)):
-        L[fromstr[i]] = tostr[i]
-    return ''.join(L)
-
-
-
-####################################################################
-import re as _re
-
-class _multimap:
-    """Helper class for combining multiple mappings.
-
-    Used by .{safe_,}substitute() to combine the mapping and keyword
-    arguments.
-    """
-    def __init__(self, primary, secondary):
-        self._primary = primary
-        self._secondary = secondary
-
-    def __getitem__(self, key):
-        try:
-            return self._primary[key]
-        except KeyError:
-            return self._secondary[key]
-
-
-class _TemplateMetaclass(type):
-    pattern = r"""
-    %(delim)s(?:
-      (?P<escaped>%(delim)s) |   # Escape sequence of two delimiters
-      (?P<named>%(id)s)      |   # delimiter and a Python identifier
-      {(?P<braced>%(id)s)}   |   # delimiter and a braced identifier
-      (?P<invalid>)              # Other ill-formed delimiter exprs
-    )
-    """
-
-    def __init__(cls, name, bases, dct):
-        super(_TemplateMetaclass, cls).__init__(name, bases, dct)
-        if 'pattern' in dct:
-            pattern = cls.pattern
-        else:
-            pattern = _TemplateMetaclass.pattern % {
-                'delim' : _re.escape(cls.delimiter),
-                'id'    : cls.idpattern,
-                }
-        cls.pattern = _re.compile(pattern, _re.IGNORECASE | _re.VERBOSE)
-
-
-class Template:
-    """A string class for supporting $-substitutions."""
-    __metaclass__ = _TemplateMetaclass
-
-    delimiter = '$'
-    idpattern = r'[_a-z][_a-z0-9]*'
-
-    def __init__(self, template):
-        self.template = template
-
-    # Search for $$, $identifier, ${identifier}, and any bare $'s
-
-    def _invalid(self, mo):
-        i = mo.start('invalid')
-        lines = self.template[:i].splitlines(True)
-        if not lines:
-            colno = 1
-            lineno = 1
-        else:
-            colno = i - len(''.join(lines[:-1]))
-            lineno = len(lines)
-        raise ValueError('Invalid placeholder in string: line %d, col %d' %
-                         (lineno, colno))
-
-    def substitute(self, *args, **kws):
-        if len(args) > 1:
-            raise TypeError('Too many positional arguments')
-        if not args:
-            mapping = kws
-        elif kws:
-            mapping = _multimap(kws, args[0])
-        else:
-            mapping = args[0]
-        # Helper function for .sub()
-        def convert(mo):
-            # Check the most common path first.
-            named = mo.group('named') or mo.group('braced')
-            if named is not None:
-                val = mapping[named]
-                # We use this idiom instead of str() because the latter will
-                # fail if val is a Unicode containing non-ASCII characters.
-                return '%s' % val
-            if mo.group('escaped') is not None:
-                return self.delimiter
-            if mo.group('invalid') is not None:
-                self._invalid(mo)
-            raise ValueError('Unrecognized named group in pattern',
-                             self.pattern)
-        return self.pattern.sub(convert, self.template)
-
-    def safe_substitute(self, *args, **kws):
-        if len(args) > 1:
-            raise TypeError('Too many positional arguments')
-        if not args:
-            mapping = kws
-        elif kws:
-            mapping = _multimap(kws, args[0])
-        else:
-            mapping = args[0]
-        # Helper function for .sub()
-        def convert(mo):
-            named = mo.group('named')
-            if named is not None:
-                try:
-                    # We use this idiom instead of str() because the latter
-                    # will fail if val is a Unicode containing non-ASCII
-                    return '%s' % mapping[named]
-                except KeyError:
-                    return self.delimiter + named
-            braced = mo.group('braced')
-            if braced is not None:
-                try:
-                    return '%s' % mapping[braced]
-                except KeyError:
-                    return self.delimiter + '{' + braced + '}'
-            if mo.group('escaped') is not None:
-                return self.delimiter
-            if mo.group('invalid') is not None:
-                return self.delimiter
-            raise ValueError('Unrecognized named group in pattern',
-                             self.pattern)
-        return self.pattern.sub(convert, self.template)
-
-
-
-####################################################################
-# NOTE: Everything below here is deprecated.  Use string methods instead.
-# This stuff will go away in Python 3.0.
-
-# Backward compatible names for exceptions
-index_error = ValueError
-atoi_error = ValueError
-atof_error = ValueError
-atol_error = ValueError
-
-# convert UPPER CASE letters to lower case
-def lower(s):
-    """lower(s) -> string
-
-    Return a copy of the string s converted to lowercase.
-
-    """
-    return s.lower()
-
-# Convert lower case letters to UPPER CASE
-def upper(s):
-    """upper(s) -> string
-
-    Return a copy of the string s converted to uppercase.
-
-    """
-    return s.upper()
-
-# Swap lower case letters and UPPER CASE
-def swapcase(s):
-    """swapcase(s) -> string
-
-    Return a copy of the string s with upper case characters
-    converted to lowercase and vice versa.
-
-    """
-    return s.swapcase()
-
-# Strip leading and trailing tabs and spaces
-def strip(s, chars=None):
-    """strip(s [,chars]) -> string
-
-    Return a copy of the string s with leading and trailing
-    whitespace removed.
-    If chars is given and not None, remove characters in chars instead.
-    If chars is unicode, S will be converted to unicode before stripping.
-
-    """
-    return s.strip(chars)
-
-# Strip leading tabs and spaces
-def lstrip(s, chars=None):
-    """lstrip(s [,chars]) -> string
-
-    Return a copy of the string s with leading whitespace removed.
-    If chars is given and not None, remove characters in chars instead.
-
-    """
-    return s.lstrip(chars)
-
-# Strip trailing tabs and spaces
-def rstrip(s, chars=None):
-    """rstrip(s [,chars]) -> string
-
-    Return a copy of the string s with trailing whitespace removed.
-    If chars is given and not None, remove characters in chars instead.
-
-    """
-    return s.rstrip(chars)
-
-
-# Split a string into a list of space/tab-separated words
-def split(s, sep=None, maxsplit=-1):
-    """split(s [,sep [,maxsplit]]) -> list of strings
-
-    Return a list of the words in the string s, using sep as the
-    delimiter string.  If maxsplit is given, splits at no more than
-    maxsplit places (resulting in at most maxsplit+1 words).  If sep
-    is not specified or is None, any whitespace string is a separator.
-
-    (split and splitfields are synonymous)
-
-    """
-    return s.split(sep, maxsplit)
-splitfields = split
-
-# Split a string into a list of space/tab-separated words
-def rsplit(s, sep=None, maxsplit=-1):
-    """rsplit(s [,sep [,maxsplit]]) -> list of strings
-
-    Return a list of the words in the string s, using sep as the
-    delimiter string, starting at the end of the string and working
-    to the front.  If maxsplit is given, at most maxsplit splits are
-    done. If sep is not specified or is None, any whitespace string
-    is a separator.
-    """
-    return s.rsplit(sep, maxsplit)
-
-# Join fields with optional separator
-def join(words, sep = ' '):
-    """join(list [,sep]) -> string
-
-    Return a string composed of the words in list, with
-    intervening occurrences of sep.  The default separator is a
-    single space.
-
-    (joinfields and join are synonymous)
-
-    """
-    return sep.join(words)
-joinfields = join
-
-# Find substring, raise exception if not found
-def index(s, *args):
-    """index(s, sub [,start [,end]]) -> int
-
-    Like find but raises ValueError when the substring is not found.
-
-    """
-    return s.index(*args)
-
-# Find last substring, raise exception if not found
-def rindex(s, *args):
-    """rindex(s, sub [,start [,end]]) -> int
-
-    Like rfind but raises ValueError when the substring is not found.
-
-    """
-    return s.rindex(*args)
-
-# Count non-overlapping occurrences of substring
-def count(s, *args):
-    """count(s, sub[, start[,end]]) -> int
-
-    Return the number of occurrences of substring sub in string
-    s[start:end].  Optional arguments start and end are
-    interpreted as in slice notation.
-
-    """
-    return s.count(*args)
-
-# Find substring, return -1 if not found
-def find(s, *args):
-    """find(s, sub [,start [,end]]) -> in
-
-    Return the lowest index in s where substring sub is found,
-    such that sub is contained within s[start,end].  Optional
-    arguments start and end are interpreted as in slice notation.
-
-    Return -1 on failure.
-
-    """
-    return s.find(*args)
-
-# Find last substring, return -1 if not found
-def rfind(s, *args):
-    """rfind(s, sub [,start [,end]]) -> int
-
-    Return the highest index in s where substring sub is found,
-    such that sub is contained within s[start,end].  Optional
-    arguments start and end are interpreted as in slice notation.
-
-    Return -1 on failure.
-
-    """
-    return s.rfind(*args)
-
-# for a bit of speed
-_float = float
-_int = int
-_long = long
-
-# Convert string to float
-def atof(s):
-    """atof(s) -> float
-
-    Return the floating point number represented by the string s.
-
-    """
-    return _float(s)
-
-
-# Convert string to integer
-def atoi(s , base=10):
-    """atoi(s [,base]) -> int
-
-    Return the integer represented by the string s in the given
-    base, which defaults to 10.  The string s must consist of one
-    or more digits, possibly preceded by a sign.  If base is 0, it
-    is chosen from the leading characters of s, 0 for octal, 0x or
-    0X for hexadecimal.  If base is 16, a preceding 0x or 0X is
-    accepted.
-
-    """
-    return _int(s, base)
-
-
-# Convert string to long integer
-def atol(s, base=10):
-    """atol(s [,base]) -> long
-
-    Return the long integer represented by the string s in the
-    given base, which defaults to 10.  The string s must consist
-    of one or more digits, possibly preceded by a sign.  If base
-    is 0, it is chosen from the leading characters of s, 0 for
-    octal, 0x or 0X for hexadecimal.  If base is 16, a preceding
-    0x or 0X is accepted.  A trailing L or l is not accepted,
-    unless base is 0.
-
-    """
-    return _long(s, base)
-
-
-# Left-justify a string
-def ljust(s, width, *args):
-    """ljust(s, width[, fillchar]) -> string
-
-    Return a left-justified version of s, in a field of the
-    specified width, padded with spaces as needed.  The string is
-    never truncated.  If specified the fillchar is used instead of spaces.
-
-    """
-    return s.ljust(width, *args)
-
-# Right-justify a string
-def rjust(s, width, *args):
-    """rjust(s, width[, fillchar]) -> string
-
-    Return a right-justified version of s, in a field of the
-    specified width, padded with spaces as needed.  The string is
-    never truncated.  If specified the fillchar is used instead of spaces.
-
-    """
-    return s.rjust(width, *args)
-
-# Center a string
-def center(s, width, *args):
-    """center(s, width[, fillchar]) -> string
-
-    Return a center version of s, in a field of the specified
-    width. padded with spaces as needed.  The string is never
-    truncated.  If specified the fillchar is used instead of spaces.
-
-    """
-    return s.center(width, *args)
-
-# Zero-fill a number, e.g., (12, 3) --> '012' and (-3, 3) --> '-03'
-# Decadent feature: the argument may be a string or a number
-# (Use of this is deprecated; it should be a string as with ljust c.s.)
-def zfill(x, width):
-    """zfill(x, width) -> string
-
-    Pad a numeric string x with zeros on the left, to fill a field
-    of the specified width.  The string x is never truncated.
-
-    """
-    if not isinstance(x, basestring):
-        x = repr(x)
-    return x.zfill(width)
-
-# Expand tabs in a string.
-# Doesn't take non-printing chars into account, but does understand \n.
-def expandtabs(s, tabsize=8):
-    """expandtabs(s [,tabsize]) -> string
-
-    Return a copy of the string s with all tab characters replaced
-    by the appropriate number of spaces, depending on the current
-    column, and the tabsize (default 8).
-
-    """
-    return s.expandtabs(tabsize)
-
-# Character translation through look-up table.
-def translate(s, table, deletions=""):
-    """translate(s,table [,deletions]) -> string
-
-    Return a copy of the string s, where all characters occurring
-    in the optional argument deletions are removed, and the
-    remaining characters have been mapped through the given
-    translation table, which must be a string of length 256.  The
-    deletions argument is not allowed for Unicode strings.
-
-    """
-    if deletions:
-        return s.translate(table, deletions)
-    else:
-        # Add s[:0] so that if s is Unicode and table is an 8-bit string,
-        # table is converted to Unicode.  This means that table *cannot*
-        # be a dictionary -- for that feature, use u.translate() directly.
-        return s.translate(table + s[:0])
-
-# Capitalize a string, e.g. "aBc  dEf" -> "Abc  def".
-def capitalize(s):
-    """capitalize(s) -> string
-
-    Return a copy of the string s with only its first character
-    capitalized.
-
-    """
-    return s.capitalize()
-
-# Substring replacement (global)
-def replace(s, old, new, maxsplit=-1):
-    """replace (str, old, new[, maxsplit]) -> string
-
-    Return a copy of string str with all occurrences of substring
-    old replaced by new. If the optional argument maxsplit is
-    given, only the first maxsplit occurrences are replaced.
-
-    """
-    return s.replace(old, new, maxsplit)
-
-
-# Try importing optional built-in module "strop" -- if it exists,
-# it redefines some string operations that are 100-1000 times faster.
-# It also defines values for whitespace, lowercase and uppercase
-# that match <ctype.h>'s definitions.
-
-try:
-    from strop import maketrans, lowercase, uppercase, whitespace
-    letters = lowercase + uppercase
-except ImportError:
-    pass                                          # Use the original versions
diff --git a/lib/paste/util/subprocess24.py b/lib/paste/util/subprocess24.py
@@ -1,1152 +0,0 @@
-# subprocess - Subprocesses with accessible I/O streams
-#
-# For more information about this module, see PEP 324.
-#
-# This module should remain compatible with Python 2.2, see PEP 291.
-#
-# Copyright (c) 2003-2005 by Peter Astrand <astrand@lysator.liu.se>
-#
-# Licensed to PSF under a Contributor Agreement.
-# See http://www.python.org/2.4/license for licensing details.
-
-r"""subprocess - Subprocesses with accessible I/O streams
-
-This module allows you to spawn processes, connect to their
-input/output/error pipes, and obtain their return codes.  This module
-intends to replace several other, older modules and functions, like:
-
-os.system
-os.spawn*
-os.popen*
-popen2.*
-commands.*
-
-Information about how the subprocess module can be used to replace these
-modules and functions can be found below.
-
-
-
-Using the subprocess module
-===========================
-This module defines one class called Popen:
-
-class Popen(args, bufsize=0, executable=None,
-            stdin=None, stdout=None, stderr=None,
-            preexec_fn=None, close_fds=False, shell=False,
-            cwd=None, env=None, universal_newlines=False,
-            startupinfo=None, creationflags=0):
-
-
-Arguments are:
-
-args should be a string, or a sequence of program arguments.  The
-program to execute is normally the first item in the args sequence or
-string, but can be explicitly set by using the executable argument.
-
-On UNIX, with shell=False (default): In this case, the Popen class
-uses os.execvp() to execute the child program.  args should normally
-be a sequence.  A string will be treated as a sequence with the string
-as the only item (the program to execute).
-
-On UNIX, with shell=True: If args is a string, it specifies the
-command string to execute through the shell.  If args is a sequence,
-the first item specifies the command string, and any additional items
-will be treated as additional shell arguments.
-
-On Windows: the Popen class uses CreateProcess() to execute the child
-program, which operates on strings.  If args is a sequence, it will be
-converted to a string using the list2cmdline method.  Please note that
-not all MS Windows applications interpret the command line the same
-way: The list2cmdline is designed for applications using the same
-rules as the MS C runtime.
-
-bufsize, if given, has the same meaning as the corresponding argument
-to the built-in open() function: 0 means unbuffered, 1 means line
-buffered, any other positive value means use a buffer of
-(approximately) that size.  A negative bufsize means to use the system
-default, which usually means fully buffered.  The default value for
-bufsize is 0 (unbuffered).
-
-stdin, stdout and stderr specify the executed programs' standard
-input, standard output and standard error file handles, respectively.
-Valid values are PIPE, an existing file descriptor (a positive
-integer), an existing file object, and None.  PIPE indicates that a
-new pipe to the child should be created.  With None, no redirection
-will occur; the child's file handles will be inherited from the
-parent.  Additionally, stderr can be STDOUT, which indicates that the
-stderr data from the applications should be captured into the same
-file handle as for stdout.
-
-If preexec_fn is set to a callable object, this object will be called
-in the child process just before the child is executed.
-
-If close_fds is true, all file descriptors except 0, 1 and 2 will be
-closed before the child process is executed.
-
-if shell is true, the specified command will be executed through the
-shell.
-
-If cwd is not None, the current directory will be changed to cwd
-before the child is executed.
-
-If env is not None, it defines the environment variables for the new
-process.
-
-If universal_newlines is true, the file objects stdout and stderr are
-opened as a text files, but lines may be terminated by any of '\n',
-the Unix end-of-line convention, '\r', the Macintosh convention or
-'\r\n', the Windows convention.  All of these external representations
-are seen as '\n' by the Python program.  Note: This feature is only
-available if Python is built with universal newline support (the
-default).  Also, the newlines attribute of the file objects stdout,
-stdin and stderr are not updated by the communicate() method.
-
-The startupinfo and creationflags, if given, will be passed to the
-underlying CreateProcess() function.  They can specify things such as
-appearance of the main window and priority for the new process.
-(Windows only)
-
-
-This module also defines two shortcut functions:
-
-call(*args, **kwargs):
-    Run command with arguments.  Wait for command to complete, then
-    return the returncode attribute. The arguments are the same as for
-    the Popen constructor.  Example:
-
-    retcode = call(["ls", "-l"])
-
-
-Exceptions
-----------
-Exceptions raised in the child process, before the new program has
-started to execute, will be re-raised in the parent.  Additionally,
-the exception object will have one extra attribute called
-'child_traceback', which is a string containing traceback information
-from the childs point of view.
-
-The most common exception raised is OSError.  This occurs, for
-example, when trying to execute a non-existent file.  Applications
-should prepare for OSErrors.
-
-A ValueError will be raised if Popen is called with invalid arguments.
-
-
-Security
---------
-Unlike some other popen functions, this implementation will never call
-/bin/sh implicitly.  This means that all characters, including shell
-metacharacters, can safely be passed to child processes.
-
-
-Popen objects
-=============
-Instances of the Popen class have the following methods:
-
-poll()
-    Check if child process has terminated.  Returns returncode
-    attribute.
-
-wait()
-    Wait for child process to terminate.  Returns returncode attribute.
-
-communicate(input=None)
-    Interact with process: Send data to stdin.  Read data from stdout
-    and stderr, until end-of-file is reached.  Wait for process to
-    terminate.  The optional stdin argument should be a string to be
-    sent to the child process, or None, if no data should be sent to
-    the child.
-
-    communicate() returns a tuple (stdout, stderr).
-
-    Note: The data read is buffered in memory, so do not use this
-    method if the data size is large or unlimited.
-
-The following attributes are also available:
-
-stdin
-    If the stdin argument is PIPE, this attribute is a file object
-    that provides input to the child process.  Otherwise, it is None.
-
-stdout
-    If the stdout argument is PIPE, this attribute is a file object
-    that provides output from the child process.  Otherwise, it is
-    None.
-
-stderr
-    If the stderr argument is PIPE, this attribute is file object that
-    provides error output from the child process.  Otherwise, it is
-    None.
-
-pid
-    The process ID of the child process.
-
-returncode
-    The child return code.  A None value indicates that the process
-    hasn't terminated yet.  A negative value -N indicates that the
-    child was terminated by signal N (UNIX only).
-
-
-Replacing older functions with the subprocess module
-====================================================
-In this section, "a ==> b" means that b can be used as a replacement
-for a.
-
-Note: All functions in this section fail (more or less) silently if
-the executed program cannot be found; this module raises an OSError
-exception.
-
-In the following examples, we assume that the subprocess module is
-imported with "from subprocess import *".
-
-
-Replacing /bin/sh shell backquote
----------------------------------
-output=`mycmd myarg`
-==>
-output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0]
-
-
-Replacing shell pipe line
--------------------------
-output=`dmesg | grep hda`
-==>
-p1 = Popen(["dmesg"], stdout=PIPE)
-p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
-output = p2.communicate()[0]
-
-
-Replacing os.system()
----------------------
-sts = os.system("mycmd" + " myarg")
-==>
-p = Popen("mycmd" + " myarg", shell=True)
-sts = os.waitpid(p.pid, 0)
-
-Note:
-
-* Calling the program through the shell is usually not required.
-
-* It's easier to look at the returncode attribute than the
-  exitstatus.
-
-A more real-world example would look like this:
-
-try:
-    retcode = call("mycmd" + " myarg", shell=True)
-    if retcode < 0:
-        print >>sys.stderr, "Child was terminated by signal", -retcode
-    else:
-        print >>sys.stderr, "Child returned", retcode
-except OSError, e:
-    print >>sys.stderr, "Execution failed:", e
-
-
-Replacing os.spawn*
--------------------
-P_NOWAIT example:
-
-pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg")
-==>
-pid = Popen(["/bin/mycmd", "myarg"]).pid
-
-
-P_WAIT example:
-
-retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg")
-==>
-retcode = call(["/bin/mycmd", "myarg"])
-
-
-Vector example:
-
-os.spawnvp(os.P_NOWAIT, path, args)
-==>
-Popen([path] + args[1:])
-
-
-Environment example:
-
-os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env)
-==>
-Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"})
-
-
-Replacing os.popen*
--------------------
-pipe = os.popen(cmd, mode='r', bufsize)
-==>
-pipe = Popen(cmd, shell=True, bufsize=bufsize, stdout=PIPE).stdout
-
-pipe = os.popen(cmd, mode='w', bufsize)
-==>
-pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin
-
-
-(child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize)
-==>
-p = Popen(cmd, shell=True, bufsize=bufsize,
-          stdin=PIPE, stdout=PIPE, close_fds=True)
-(child_stdin, child_stdout) = (p.stdin, p.stdout)
-
-
-(child_stdin,
- child_stdout,
- child_stderr) = os.popen3(cmd, mode, bufsize)
-==>
-p = Popen(cmd, shell=True, bufsize=bufsize,
-          stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
-(child_stdin,
- child_stdout,
- child_stderr) = (p.stdin, p.stdout, p.stderr)
-
-
-(child_stdin, child_stdout_and_stderr) = os.popen4(cmd, mode, bufsize)
-==>
-p = Popen(cmd, shell=True, bufsize=bufsize,
-          stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
-(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout)
-
-
-Replacing popen2.*
-------------------
-Note: If the cmd argument to popen2 functions is a string, the command
-is executed through /bin/sh.  If it is a list, the command is directly
-executed.
-
-(child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode)
-==>
-p = Popen(["somestring"], shell=True, bufsize=bufsize
-          stdin=PIPE, stdout=PIPE, close_fds=True)
-(child_stdout, child_stdin) = (p.stdout, p.stdin)
-
-
-(child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode)
-==>
-p = Popen(["mycmd", "myarg"], bufsize=bufsize,
-          stdin=PIPE, stdout=PIPE, close_fds=True)
-(child_stdout, child_stdin) = (p.stdout, p.stdin)
-
-The popen2.Popen3 and popen3.Popen4 basically works as subprocess.Popen,
-except that:
-
-* subprocess.Popen raises an exception if the execution fails
-* the capturestderr argument is replaced with the stderr argument.
-* stdin=PIPE and stdout=PIPE must be specified.
-* popen2 closes all filedescriptors by default, but you have to specify
-  close_fds=True with subprocess.Popen.
-
-
-"""
-
-import sys
-mswindows = (sys.platform == "win32")
-
-import os
-import types
-import traceback
-
-if mswindows:
-    import threading
-    import msvcrt
-    ## @@: Changed in Paste
-    ## Since this module is only used on pre-python-2.4 systems, they probably
-    ## don't have _subprocess installed, but hopefully have the win32 stuff
-    ## installed.
-    if 1: # <-- change this to use pywin32 instead of the _subprocess driver
-        import pywintypes
-        from win32api import GetStdHandle, STD_INPUT_HANDLE, \
-                             STD_OUTPUT_HANDLE, STD_ERROR_HANDLE
-        from win32api import GetCurrentProcess, DuplicateHandle, \
-                             GetModuleFileName, GetVersion
-        from win32con import DUPLICATE_SAME_ACCESS, SW_HIDE
-        from win32pipe import CreatePipe
-        from win32process import CreateProcess, STARTUPINFO, \
-                                 GetExitCodeProcess, STARTF_USESTDHANDLES, \
-                                 STARTF_USESHOWWINDOW, CREATE_NEW_CONSOLE
-        from win32event import WaitForSingleObject, INFINITE, WAIT_OBJECT_0
-    else:
-        from _subprocess import *
-        class STARTUPINFO:
-            dwFlags = 0
-            hStdInput = None
-            hStdOutput = None
-            hStdError = None
-        class pywintypes:
-            error = IOError
-else:
-    import select
-    import errno
-    import fcntl
-    import pickle
-
-__all__ = ["Popen", "PIPE", "STDOUT", "call"]
-
-try:
-    MAXFD = os.sysconf("SC_OPEN_MAX")
-except:
-    MAXFD = 256
-
-# True/False does not exist on 2.2.0
-try:
-    False
-except NameError:
-    False = 0
-    True = 1
-
-_active = []
-
-def _cleanup():
-    for inst in _active[:]:
-        inst.poll()
-
-PIPE = -1
-STDOUT = -2
-
-
-def call(*args, **kwargs):
-    """Run command with arguments.  Wait for command to complete, then
-    return the returncode attribute.
-
-    The arguments are the same as for the Popen constructor.  Example:
-
-    retcode = call(["ls", "-l"])
-    """
-    return Popen(*args, **kwargs).wait()
-
-
-def list2cmdline(seq):
-    """
-    Translate a sequence of arguments into a command line
-    string, using the same rules as the MS C runtime:
-
-    1) Arguments are delimited by white space, which is either a
-       space or a tab.
-
-    2) A string surrounded by double quotation marks is
-       interpreted as a single argument, regardless of white space
-       contained within.  A quoted string can be embedded in an
-       argument.
-
-    3) A double quotation mark preceded by a backslash is
-       interpreted as a literal double quotation mark.
-
-    4) Backslashes are interpreted literally, unless they
-       immediately precede a double quotation mark.
-
-    5) If backslashes immediately precede a double quotation mark,
-       every pair of backslashes is interpreted as a literal
-       backslash.  If the number of backslashes is odd, the last
-       backslash escapes the next double quotation mark as
-       described in rule 3.
-    """
-
-    # See
-    # http://msdn.microsoft.com/library/en-us/vccelng/htm/progs_12.asp
-    result = []
-    needquote = False
-    for arg in seq:
-        bs_buf = []
-
-        # Add a space to separate this argument from the others
-        if result:
-            result.append(' ')
-
-        needquote = (" " in arg) or ("\t" in arg)
-        if needquote:
-            result.append('"')
-
-        for c in arg:
-            if c == '\\':
-                # Don't know if we need to double yet.
-                bs_buf.append(c)
-            elif c == '"':
-                # Double backspaces.
-                result.append('\\' * len(bs_buf)*2)
-                bs_buf = []
-                result.append('\\"')
-            else:
-                # Normal char
-                if bs_buf:
-                    result.extend(bs_buf)
-                    bs_buf = []
-                result.append(c)
-
-        # Add remaining backspaces, if any.
-        if bs_buf:
-            result.extend(bs_buf)
-
-        if needquote:
-            result.extend(bs_buf)
-            result.append('"')
-
-    return ''.join(result)
-
-
-class Popen(object):
-    def __init__(self, args, bufsize=0, executable=None,
-                 stdin=None, stdout=None, stderr=None,
-                 preexec_fn=None, close_fds=False, shell=False,
-                 cwd=None, env=None, universal_newlines=False,
-                 startupinfo=None, creationflags=0):
-        """Create new Popen instance."""
-        _cleanup()
-
-        if not isinstance(bufsize, (int, long)):
-            raise TypeError("bufsize must be an integer")
-
-        if mswindows:
-            if preexec_fn is not None:
-                raise ValueError("preexec_fn is not supported on Windows "
-                                 "platforms")
-            if close_fds:
-                raise ValueError("close_fds is not supported on Windows "
-                                 "platforms")
-        else:
-            # POSIX
-            if startupinfo is not None:
-                raise ValueError("startupinfo is only supported on Windows "
-                                 "platforms")
-            if creationflags != 0:
-                raise ValueError("creationflags is only supported on Windows "
-                                 "platforms")
-
-        self.stdin = None
-        self.stdout = None
-        self.stderr = None
-        self.pid = None
-        self.returncode = None
-        self.universal_newlines = universal_newlines
-
-        # Input and output objects. The general principle is like
-        # this:
-        #
-        # Parent                   Child
-        # ------                   -----
-        # p2cwrite   ---stdin--->  p2cread
-        # c2pread    <--stdout---  c2pwrite
-        # errread    <--stderr---  errwrite
-        #
-        # On POSIX, the child objects are file descriptors.  On
-        # Windows, these are Windows file handles.  The parent objects
-        # are file descriptors on both platforms.  The parent objects
-        # are None when not using PIPEs. The child objects are None
-        # when not redirecting.
-
-        (p2cread, p2cwrite,
-         c2pread, c2pwrite,
-         errread, errwrite) = self._get_handles(stdin, stdout, stderr)
-
-        self._execute_child(args, executable, preexec_fn, close_fds,
-                            cwd, env, universal_newlines,
-                            startupinfo, creationflags, shell,
-                            p2cread, p2cwrite,
-                            c2pread, c2pwrite,
-                            errread, errwrite)
-
-        if p2cwrite:
-            self.stdin = os.fdopen(p2cwrite, 'wb', bufsize)
-        if c2pread:
-            if universal_newlines:
-                self.stdout = os.fdopen(c2pread, 'rU', bufsize)
-            else:
-                self.stdout = os.fdopen(c2pread, 'rb', bufsize)
-        if errread:
-            if universal_newlines:
-                self.stderr = os.fdopen(errread, 'rU', bufsize)
-            else:
-                self.stderr = os.fdopen(errread, 'rb', bufsize)
-
-        _active.append(self)
-
-
-    def _translate_newlines(self, data):
-        data = data.replace("\r\n", "\n")
-        data = data.replace("\r", "\n")
-        return data
-
-
-    if mswindows:
-        #
-        # Windows methods
-        #
-        def _get_handles(self, stdin, stdout, stderr):
-            """Construct and return tupel with IO objects:
-            p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
-            """
-            if stdin == None and stdout == None and stderr == None:
-                return (None, None, None, None, None, None)
-
-            p2cread, p2cwrite = None, None
-            c2pread, c2pwrite = None, None
-            errread, errwrite = None, None
-
-            if stdin == None:
-                p2cread = GetStdHandle(STD_INPUT_HANDLE)
-            elif stdin == PIPE:
-                p2cread, p2cwrite = CreatePipe(None, 0)
-                # Detach and turn into fd
-                p2cwrite = p2cwrite.Detach()
-                p2cwrite = msvcrt.open_osfhandle(p2cwrite, 0)
-            elif type(stdin) == types.IntType:
-                p2cread = msvcrt.get_osfhandle(stdin)
-            else:
-                # Assuming file-like object
-                p2cread = msvcrt.get_osfhandle(stdin.fileno())
-            p2cread = self._make_inheritable(p2cread)
-
-            if stdout == None:
-                c2pwrite = GetStdHandle(STD_OUTPUT_HANDLE)
-            elif stdout == PIPE:
-                c2pread, c2pwrite = CreatePipe(None, 0)
-                # Detach and turn into fd
-                c2pread = c2pread.Detach()
-                c2pread = msvcrt.open_osfhandle(c2pread, 0)
-            elif type(stdout) == types.IntType:
-                c2pwrite = msvcrt.get_osfhandle(stdout)
-            else:
-                # Assuming file-like object
-                c2pwrite = msvcrt.get_osfhandle(stdout.fileno())
-            c2pwrite = self._make_inheritable(c2pwrite)
-
-            if stderr == None:
-                errwrite = GetStdHandle(STD_ERROR_HANDLE)
-            elif stderr == PIPE:
-                errread, errwrite = CreatePipe(None, 0)
-                # Detach and turn into fd
-                errread = errread.Detach()
-                errread = msvcrt.open_osfhandle(errread, 0)
-            elif stderr == STDOUT:
-                errwrite = c2pwrite
-            elif type(stderr) == types.IntType:
-                errwrite = msvcrt.get_osfhandle(stderr)
-            else:
-                # Assuming file-like object
-                errwrite = msvcrt.get_osfhandle(stderr.fileno())
-            errwrite = self._make_inheritable(errwrite)
-
-            return (p2cread, p2cwrite,
-                    c2pread, c2pwrite,
-                    errread, errwrite)
-
-
-        def _make_inheritable(self, handle):
-            """Return a duplicate of handle, which is inheritable"""
-            return DuplicateHandle(GetCurrentProcess(), handle,
-                                   GetCurrentProcess(), 0, 1,
-                                   DUPLICATE_SAME_ACCESS)
-
-
-        def _find_w9xpopen(self):
-            """Find and return absolut path to w9xpopen.exe"""
-            w9xpopen = os.path.join(os.path.dirname(GetModuleFileName(0)),
-                                    "w9xpopen.exe")
-            if not os.path.exists(w9xpopen):
-                # Eeek - file-not-found - possibly an embedding
-                # situation - see if we can locate it in sys.exec_prefix
-                w9xpopen = os.path.join(os.path.dirname(sys.exec_prefix),
-                                        "w9xpopen.exe")
-                if not os.path.exists(w9xpopen):
-                    raise RuntimeError("Cannot locate w9xpopen.exe, which is "
-                                       "needed for Popen to work with your "
-                                       "shell or platform.")
-            return w9xpopen
-
-
-        def _execute_child(self, args, executable, preexec_fn, close_fds,
-                           cwd, env, universal_newlines,
-                           startupinfo, creationflags, shell,
-                           p2cread, p2cwrite,
-                           c2pread, c2pwrite,
-                           errread, errwrite):
-            """Execute program (MS Windows version)"""
-
-            if not isinstance(args, types.StringTypes):
-                args = list2cmdline(args)
-
-            # Process startup details
-            default_startupinfo = STARTUPINFO()
-            if startupinfo == None:
-                startupinfo = default_startupinfo
-            if not None in (p2cread, c2pwrite, errwrite):
-                startupinfo.dwFlags |= STARTF_USESTDHANDLES
-                startupinfo.hStdInput = p2cread
-                startupinfo.hStdOutput = c2pwrite
-                startupinfo.hStdError = errwrite
-
-            if shell:
-                default_startupinfo.dwFlags |= STARTF_USESHOWWINDOW
-                default_startupinfo.wShowWindow = SW_HIDE
-                comspec = os.environ.get("COMSPEC", "cmd.exe")
-                args = comspec + " /c " + args
-                if (GetVersion() >= 0x80000000L or
-                        os.path.basename(comspec).lower() == "command.com"):
-                    # Win9x, or using command.com on NT. We need to
-                    # use the w9xpopen intermediate program. For more
-                    # information, see KB Q150956
-                    # (http://web.archive.org/web/20011105084002/http://support.microsoft.com/support/kb/articles/Q150/9/56.asp)
-                    w9xpopen = self._find_w9xpopen()
-                    args = '"%s" %s' % (w9xpopen, args)
-                    # Not passing CREATE_NEW_CONSOLE has been known to
-                    # cause random failures on win9x.  Specifically a
-                    # dialog: "Your program accessed mem currently in
-                    # use at xxx" and a hopeful warning about the
-                    # stability of your system.  Cost is Ctrl+C wont
-                    # kill children.
-                    creationflags |= CREATE_NEW_CONSOLE
-
-            # Start the process
-            try:
-                hp, ht, pid, tid = CreateProcess(executable, args,
-                                         # no special security
-                                         None, None,
-                                         # must inherit handles to pass std
-                                         # handles
-                                         1,
-                                         creationflags,
-                                         env,
-                                         cwd,
-                                         startupinfo)
-            except pywintypes.error, e:
-                # Translate pywintypes.error to WindowsError, which is
-                # a subclass of OSError.  FIXME: We should really
-                # translate errno using _sys_errlist (or simliar), but
-                # how can this be done from Python?
-                raise WindowsError(*e.args)
-
-            # Retain the process handle, but close the thread handle
-            self._handle = hp
-            self.pid = pid
-            ht.Close()
-
-            # Child is launched. Close the parent's copy of those pipe
-            # handles that only the child should have open.  You need
-            # to make sure that no handles to the write end of the
-            # output pipe are maintained in this process or else the
-            # pipe will not close when the child process exits and the
-            # ReadFile will hang.
-            if p2cread != None:
-                p2cread.Close()
-            if c2pwrite != None:
-                c2pwrite.Close()
-            if errwrite != None:
-                errwrite.Close()
-
-
-        def poll(self):
-            """Check if child process has terminated.  Returns returncode
-            attribute."""
-            if self.returncode == None:
-                if WaitForSingleObject(self._handle, 0) == WAIT_OBJECT_0:
-                    self.returncode = GetExitCodeProcess(self._handle)
-                    _active.remove(self)
-            return self.returncode
-
-
-        def wait(self):
-            """Wait for child process to terminate.  Returns returncode
-            attribute."""
-            if self.returncode == None:
-                obj = WaitForSingleObject(self._handle, INFINITE)
-                self.returncode = GetExitCodeProcess(self._handle)
-                _active.remove(self)
-            return self.returncode
-
-
-        def _readerthread(self, fh, buffer):
-            buffer.append(fh.read())
-
-
-        def communicate(self, input=None):
-            """Interact with process: Send data to stdin.  Read data from
-            stdout and stderr, until end-of-file is reached.  Wait for
-            process to terminate.  The optional input argument should be a
-            string to be sent to the child process, or None, if no data
-            should be sent to the child.
-
-            communicate() returns a tuple (stdout, stderr)."""
-            stdout = None # Return
-            stderr = None # Return
-
-            if self.stdout:
-                stdout = []
-                stdout_thread = threading.Thread(target=self._readerthread,
-                                                 args=(self.stdout, stdout))
-                stdout_thread.setDaemon(True)
-                stdout_thread.start()
-            if self.stderr:
-                stderr = []
-                stderr_thread = threading.Thread(target=self._readerthread,
-                                                 args=(self.stderr, stderr))
-                stderr_thread.setDaemon(True)
-                stderr_thread.start()
-
-            if self.stdin:
-                if input != None:
-                    self.stdin.write(input)
-                self.stdin.close()
-
-            if self.stdout:
-                stdout_thread.join()
-            if self.stderr:
-                stderr_thread.join()
-
-            # All data exchanged.  Translate lists into strings.
-            if stdout != None:
-                stdout = stdout[0]
-            if stderr != None:
-                stderr = stderr[0]
-
-            # Translate newlines, if requested.  We cannot let the file
-            # object do the translation: It is based on stdio, which is
-            # impossible to combine with select (unless forcing no
-            # buffering).
-            if self.universal_newlines and hasattr(open, 'newlines'):
-                if stdout:
-                    stdout = self._translate_newlines(stdout)
-                if stderr:
-                    stderr = self._translate_newlines(stderr)
-
-            self.wait()
-            return (stdout, stderr)
-
-    else:
-        #
-        # POSIX methods
-        #
-        def _get_handles(self, stdin, stdout, stderr):
-            """Construct and return tupel with IO objects:
-            p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite
-            """
-            p2cread, p2cwrite = None, None
-            c2pread, c2pwrite = None, None
-            errread, errwrite = None, None
-
-            if stdin == None:
-                pass
-            elif stdin == PIPE:
-                p2cread, p2cwrite = os.pipe()
-            elif type(stdin) == types.IntType:
-                p2cread = stdin
-            else:
-                # Assuming file-like object
-                p2cread = stdin.fileno()
-
-            if stdout == None:
-                pass
-            elif stdout == PIPE:
-                c2pread, c2pwrite = os.pipe()
-            elif type(stdout) == types.IntType:
-                c2pwrite = stdout
-            else:
-                # Assuming file-like object
-                c2pwrite = stdout.fileno()
-
-            if stderr == None:
-                pass
-            elif stderr == PIPE:
-                errread, errwrite = os.pipe()
-            elif stderr == STDOUT:
-                errwrite = c2pwrite
-            elif type(stderr) == types.IntType:
-                errwrite = stderr
-            else:
-                # Assuming file-like object
-                errwrite = stderr.fileno()
-
-            return (p2cread, p2cwrite,
-                    c2pread, c2pwrite,
-                    errread, errwrite)
-
-
-        def _set_cloexec_flag(self, fd):
-            try:
-                cloexec_flag = fcntl.FD_CLOEXEC
-            except AttributeError:
-                cloexec_flag = 1
-
-            old = fcntl.fcntl(fd, fcntl.F_GETFD)
-            fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag)
-
-
-        def _close_fds(self, but):
-            for i in range(3, MAXFD):
-                if i == but:
-                    continue
-                try:
-                    os.close(i)
-                except:
-                    pass
-
-
-        def _execute_child(self, args, executable, preexec_fn, close_fds,
-                           cwd, env, universal_newlines,
-                           startupinfo, creationflags, shell,
-                           p2cread, p2cwrite,
-                           c2pread, c2pwrite,
-                           errread, errwrite):
-            """Execute program (POSIX version)"""
-
-            if isinstance(args, types.StringTypes):
-                args = [args]
-
-            if shell:
-                args = ["/bin/sh", "-c"] + args
-
-            if executable == None:
-                executable = args[0]
-
-            # For transferring possible exec failure from child to parent
-            # The first char specifies the exception type: 0 means
-            # OSError, 1 means some other error.
-            errpipe_read, errpipe_write = os.pipe()
-            self._set_cloexec_flag(errpipe_write)
-
-            self.pid = os.fork()
-            if self.pid == 0:
-                # Child
-                try:
-                    # Close parent's pipe ends
-                    if p2cwrite:
-                        os.close(p2cwrite)
-                    if c2pread:
-                        os.close(c2pread)
-                    if errread:
-                        os.close(errread)
-                    os.close(errpipe_read)
-
-                    # Dup fds for child
-                    if p2cread:
-                        os.dup2(p2cread, 0)
-                    if c2pwrite:
-                        os.dup2(c2pwrite, 1)
-                    if errwrite:
-                        os.dup2(errwrite, 2)
-
-                    # Close pipe fds.  Make sure we doesn't close the same
-                    # fd more than once.
-                    if p2cread:
-                        os.close(p2cread)
-                    if c2pwrite and c2pwrite not in (p2cread,):
-                        os.close(c2pwrite)
-                    if errwrite and errwrite not in (p2cread, c2pwrite):
-                        os.close(errwrite)
-
-                    # Close all other fds, if asked for
-                    if close_fds:
-                        self._close_fds(but=errpipe_write)
-
-                    if cwd != None:
-                        os.chdir(cwd)
-
-                    if preexec_fn:
-                        apply(preexec_fn)
-
-                    if env == None:
-                        os.execvp(executable, args)
-                    else:
-                        os.execvpe(executable, args, env)
-
-                except:
-                    exc_type, exc_value, tb = sys.exc_info()
-                    # Save the traceback and attach it to the exception object
-                    exc_lines = traceback.format_exception(exc_type,
-                                                           exc_value,
-                                                           tb)
-                    exc_value.child_traceback = ''.join(exc_lines)
-                    os.write(errpipe_write, pickle.dumps(exc_value))
-
-                # This exitcode won't be reported to applications, so it
-                # really doesn't matter what we return.
-                os._exit(255)
-
-            # Parent
-            os.close(errpipe_write)
-            if p2cread and p2cwrite:
-                os.close(p2cread)
-            if c2pwrite and c2pread:
-                os.close(c2pwrite)
-            if errwrite and errread:
-                os.close(errwrite)
-
-            # Wait for exec to fail or succeed; possibly raising exception
-            data = os.read(errpipe_read, 1048576) # Exceptions limited to 1 MB
-            os.close(errpipe_read)
-            if data != "":
-                os.waitpid(self.pid, 0)
-                child_exception = pickle.loads(data)
-                raise child_exception
-
-
-        def _handle_exitstatus(self, sts):
-            if os.WIFSIGNALED(sts):
-                self.returncode = -os.WTERMSIG(sts)
-            elif os.WIFEXITED(sts):
-                self.returncode = os.WEXITSTATUS(sts)
-            else:
-                # Should never happen
-                raise RuntimeError("Unknown child exit status!")
-
-            _active.remove(self)
-
-
-        def poll(self):
-            """Check if child process has terminated.  Returns returncode
-            attribute."""
-            if self.returncode == None:
-                try:
-                    pid, sts = os.waitpid(self.pid, os.WNOHANG)
-                    if pid == self.pid:
-                        self._handle_exitstatus(sts)
-                except os.error:
-                    pass
-            return self.returncode
-
-
-        def wait(self):
-            """Wait for child process to terminate.  Returns returncode
-            attribute."""
-            if self.returncode == None:
-                pid, sts = os.waitpid(self.pid, 0)
-                self._handle_exitstatus(sts)
-            return self.returncode
-
-
-        def communicate(self, input=None):
-            """Interact with process: Send data to stdin.  Read data from
-            stdout and stderr, until end-of-file is reached.  Wait for
-            process to terminate.  The optional input argument should be a
-            string to be sent to the child process, or None, if no data
-            should be sent to the child.
-
-            communicate() returns a tuple (stdout, stderr)."""
-            read_set = []
-            write_set = []
-            stdout = None # Return
-            stderr = None # Return
-
-            if self.stdin:
-                # Flush stdio buffer.  This might block, if the user has
-                # been writing to .stdin in an uncontrolled fashion.
-                self.stdin.flush()
-                if input:
-                    write_set.append(self.stdin)
-                else:
-                    self.stdin.close()
-            if self.stdout:
-                read_set.append(self.stdout)
-                stdout = []
-            if self.stderr:
-                read_set.append(self.stderr)
-                stderr = []
-
-            while read_set or write_set:
-                rlist, wlist, xlist = select.select(read_set, write_set, [])
-
-                if self.stdin in wlist:
-                    # When select has indicated that the file is writable,
-                    # we can write up to PIPE_BUF bytes without risk
-                    # blocking.  POSIX defines PIPE_BUF >= 512
-                    bytes_written = os.write(self.stdin.fileno(), input[:512])
-                    input = input[bytes_written:]
-                    if not input:
-                        self.stdin.close()
-                        write_set.remove(self.stdin)
-
-                if self.stdout in rlist:
-                    data = os.read(self.stdout.fileno(), 1024)
-                    if data == "":
-                        self.stdout.close()
-                        read_set.remove(self.stdout)
-                    stdout.append(data)
-
-                if self.stderr in rlist:
-                    data = os.read(self.stderr.fileno(), 1024)
-                    if data == "":
-                        self.stderr.close()
-                        read_set.remove(self.stderr)
-                    stderr.append(data)
-
-            # All data exchanged.  Translate lists into strings.
-            if stdout != None:
-                stdout = ''.join(stdout)
-            if stderr != None:
-                stderr = ''.join(stderr)
-
-            # Translate newlines, if requested.  We cannot let the file
-            # object do the translation: It is based on stdio, which is
-            # impossible to combine with select (unless forcing no
-            # buffering).
-            if self.universal_newlines and hasattr(open, 'newlines'):
-                if stdout:
-                    stdout = self._translate_newlines(stdout)
-                if stderr:
-                    stderr = self._translate_newlines(stderr)
-
-            self.wait()
-            return (stdout, stderr)
-
-
-def _demo_posix():
-    #
-    # Example 1: Simple redirection: Get process list
-    #
-    plist = Popen(["ps"], stdout=PIPE).communicate()[0]
-    print "Process list:"
-    print plist
-
-    #
-    # Example 2: Change uid before executing child
-    #
-    if os.getuid() == 0:
-        p = Popen(["id"], preexec_fn=lambda: os.setuid(100))
-        p.wait()
-
-    #
-    # Example 3: Connecting several subprocesses
-    #
-    print "Looking for 'hda'..."
-    p1 = Popen(["dmesg"], stdout=PIPE)
-    p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
-    print repr(p2.communicate()[0])
-
-    #
-    # Example 4: Catch execution error
-    #
-    print
-    print "Trying a weird file..."
-    try:
-        print Popen(["/this/path/does/not/exist"]).communicate()
-    except OSError, e:
-        if e.errno == errno.ENOENT:
-            print "The file didn't exist.  I thought so..."
-            print "Child traceback:"
-            print e.child_traceback
-        else:
-            print "Error", e.errno
-    else:
-        print >>sys.stderr, "Gosh.  No error."
-
-
-def _demo_windows():
-    #
-    # Example 1: Connecting several subprocesses
-    #
-    print "Looking for 'PROMPT' in set output..."
-    p1 = Popen("set", stdout=PIPE, shell=True)
-    p2 = Popen('find "PROMPT"', stdin=p1.stdout, stdout=PIPE)
-    print repr(p2.communicate()[0])
-
-    #
-    # Example 2: Simple execution of program
-    #
-    print "Executing calc..."
-    p = Popen("calc")
-    p.wait()
-
-
-if __name__ == "__main__":
-    if mswindows:
-        _demo_windows()
-    else:
-        _demo_posix()
diff --git a/lib/paste/util/template.py b/lib/paste/util/template.py
@@ -1,758 +0,0 @@
-"""
-A small templating language
-
-This implements a small templating language for use internally in
-Paste and Paste Script.  This language implements if/elif/else,
-for/continue/break, expressions, and blocks of Python code.  The
-syntax is::
-
-  {{any expression (function calls etc)}}
-  {{any expression | filter}}
-  {{for x in y}}...{{endfor}}
-  {{if x}}x{{elif y}}y{{else}}z{{endif}}
-  {{py:x=1}}
-  {{py:
-  def foo(bar):
-      return 'baz'
-  }}
-  {{default var = default_value}}
-  {{# comment}}
-
-You use this with the ``Template`` class or the ``sub`` shortcut.
-The ``Template`` class takes the template string and the name of
-the template (for errors) and a default namespace.  Then (like
-``string.Template``) you can call the ``tmpl.substitute(**kw)``
-method to make a substitution (or ``tmpl.substitute(a_dict)``).
-
-``sub(content, **kw)`` substitutes the template immediately.  You
-can use ``__name='tmpl.html'`` to set the name of the template.
-
-If there are syntax errors ``TemplateError`` will be raised.
-"""
-
-import re
-import sys
-import cgi
-import urllib
-from paste.util.looper import looper
-
-__all__ = ['TemplateError', 'Template', 'sub', 'HTMLTemplate',
-           'sub_html', 'html', 'bunch']
-
-token_re = re.compile(r'\{\{|\}\}')
-in_re = re.compile(r'\s+in\s+')
-var_re = re.compile(r'^[a-z_][a-z0-9_]*$', re.I)
-
-class TemplateError(Exception):
-    """Exception raised while parsing a template
-    """
-
-    def __init__(self, message, position, name=None):
-        self.message = message
-        self.position = position
-        self.name = name
-
-    def __str__(self):
-        msg = '%s at line %s column %s' % (
-            self.message, self.position[0], self.position[1])
-        if self.name:
-            msg += ' in %s' % self.name
-        return msg
-
-class _TemplateContinue(Exception):
-    pass
-
-class _TemplateBreak(Exception):
-    pass
-
-class Template(object):
-
-    default_namespace = {
-        'start_braces': '{{',
-        'end_braces': '}}',
-        'looper': looper,
-        }
-
-    default_encoding = 'utf8'
-
-    def __init__(self, content, name=None, namespace=None):
-        self.content = content
-        self._unicode = isinstance(content, unicode)
-        self.name = name
-        self._parsed = parse(content, name=name)
-        if namespace is None:
-            namespace = {}
-        self.namespace = namespace
-
-    def from_filename(cls, filename, namespace=None, encoding=None):
-        f = open(filename, 'rb')
-        c = f.read()
-        f.close()
-        if encoding:
-            c = c.decode(encoding)
-        return cls(content=c, name=filename, namespace=namespace)
-
-    from_filename = classmethod(from_filename)
-
-    def __repr__(self):
-        return '<%s %s name=%r>' % (
-            self.__class__.__name__,
-            hex(id(self))[2:], self.name)
-
-    def substitute(self, *args, **kw):
-        if args:
-            if kw:
-                raise TypeError(
-                    "You can only give positional *or* keyword arguments")
-            if len(args) > 1:
-                raise TypeError(
-                    "You can only give on positional argument")
-            kw = args[0]
-        ns = self.default_namespace.copy()
-        ns.update(self.namespace)
-        ns.update(kw)
-        result = self._interpret(ns)
-        return result
-
-    def _interpret(self, ns):
-        __traceback_hide__ = True
-        parts = []
-        self._interpret_codes(self._parsed, ns, out=parts)
-        return ''.join(parts)
-
-    def _interpret_codes(self, codes, ns, out):
-        __traceback_hide__ = True
-        for item in codes:
-            if isinstance(item, basestring):
-                out.append(item)
-            else:
-                self._interpret_code(item, ns, out)
-
-    def _interpret_code(self, code, ns, out):
-        __traceback_hide__ = True
-        name, pos = code[0], code[1]
-        if name == 'py':
-            self._exec(code[2], ns, pos)
-        elif name == 'continue':
-            raise _TemplateContinue()
-        elif name == 'break':
-            raise _TemplateBreak()
-        elif name == 'for':
-            vars, expr, content = code[2], code[3], code[4]
-            expr = self._eval(expr, ns, pos)
-            self._interpret_for(vars, expr, content, ns, out)
-        elif name == 'cond':
-            parts = code[2:]
-            self._interpret_if(parts, ns, out)
-        elif name == 'expr':
-            parts = code[2].split('|')
-            base = self._eval(parts[0], ns, pos)
-            for part in parts[1:]:
-                func = self._eval(part, ns, pos)
-                base = func(base)
-            out.append(self._repr(base, pos))
-        elif name == 'default':
-            var, expr = code[2], code[3]
-            if var not in ns:
-                result = self._eval(expr, ns, pos)
-                ns[var] = result
-        elif name == 'comment':
-            return
-        else:
-            assert 0, "Unknown code: %r" % name
-
-    def _interpret_for(self, vars, expr, content, ns, out):
-        __traceback_hide__ = True
-        for item in expr:
-            if len(vars) == 1:
-                ns[vars[0]] = item
-            else:
-                if len(vars) != len(item):
-                    raise ValueError(
-                        'Need %i items to unpack (got %i items)'
-                        % (len(vars), len(item)))
-                for name, value in zip(vars, item):
-                    ns[name] = value
-            try:
-                self._interpret_codes(content, ns, out)
-            except _TemplateContinue:
-                continue
-            except _TemplateBreak:
-                break
-
-    def _interpret_if(self, parts, ns, out):
-        __traceback_hide__ = True
-        # @@: if/else/else gets through
-        for part in parts:
-            assert not isinstance(part, basestring)
-            name, pos = part[0], part[1]
-            if name == 'else':
-                result = True
-            else:
-                result = self._eval(part[2], ns, pos)
-            if result:
-                self._interpret_codes(part[3], ns, out)
-                break
-
-    def _eval(self, code, ns, pos):
-        __traceback_hide__ = True
-        try:
-            value = eval(code, ns)
-            return value
-        except:
-            exc_info = sys.exc_info()
-            e = exc_info[1]
-            if getattr(e, 'args'):
-                arg0 = e.args[0]
-            else:
-                arg0 = str(e)
-            e.args = (self._add_line_info(arg0, pos),)
-            raise exc_info[0], e, exc_info[2]
-
-    def _exec(self, code, ns, pos):
-        __traceback_hide__ = True
-        try:
-            exec code in ns
-        except:
-            exc_info = sys.exc_info()
-            e = exc_info[1]
-            e.args = (self._add_line_info(e.args[0], pos),)
-            raise exc_info[0], e, exc_info[2]
-
-    def _repr(self, value, pos):
-        __traceback_hide__ = True
-        try:
-            if value is None:
-                return ''
-            if self._unicode:
-                try:
-                    value = unicode(value)
-                except UnicodeDecodeError:
-                    value = str(value)
-            else:
-                value = str(value)
-        except:
-            exc_info = sys.exc_info()
-            e = exc_info[1]
-            e.args = (self._add_line_info(e.args[0], pos),)
-            raise exc_info[0], e, exc_info[2]
-        else:
-            if self._unicode and isinstance(value, str):
-                if not self.decode_encoding:
-                    raise UnicodeDecodeError(
-                        'Cannot decode str value %r into unicode '
-                        '(no default_encoding provided)' % value)
-                value = value.decode(self.default_encoding)
-            elif not self._unicode and isinstance(value, unicode):
-                if not self.decode_encoding:
-                    raise UnicodeEncodeError(
-                        'Cannot encode unicode value %r into str '
-                        '(no default_encoding provided)' % value)
-                value = value.encode(self.default_encoding)
-            return value
-        
-
-    def _add_line_info(self, msg, pos):
-        msg = "%s at line %s column %s" % (
-            msg, pos[0], pos[1])
-        if self.name:
-            msg += " in file %s" % self.name
-        return msg
-
-def sub(content, **kw):
-    name = kw.get('__name')
-    tmpl = Template(content, name=name)
-    return tmpl.substitute(kw)
-    return result
-
-def paste_script_template_renderer(content, vars, filename=None):
-    tmpl = Template(content, name=filename)
-    return tmpl.substitute(vars)
-
-class bunch(dict):
-
-    def __init__(self, **kw):
-        for name, value in kw.items():
-            setattr(self, name, value)
-
-    def __setattr__(self, name, value):
-        self[name] = value
-
-    def __getattr__(self, name):
-        try:
-            return self[name]
-        except KeyError:
-            raise AttributeError(name)
-
-    def __getitem__(self, key):
-        if 'default' in self:
-            try:
-                return dict.__getitem__(self, key)
-            except KeyError:
-                return dict.__getitem__(self, 'default')
-        else:
-            return dict.__getitem__(self, key)
-
-    def __repr__(self):
-        items = [
-            (k, v) for k, v in self.items()]
-        items.sort()
-        return '<%s %s>' % (
-            self.__class__.__name__,
-            ' '.join(['%s=%r' % (k, v) for k, v in items]))
-
-############################################################
-## HTML Templating
-############################################################
-
-class html(object):
-    def __init__(self, value):
-        self.value = value
-    def __str__(self):
-        return self.value
-    def __repr__(self):
-        return '<%s %r>' % (
-            self.__class__.__name__, self.value)
-
-def html_quote(value):
-    if value is None:
-        return ''
-    if not isinstance(value, basestring):
-        if hasattr(value, '__unicode__'):
-            value = unicode(value)
-        else:
-            value = str(value)
-    value = cgi.escape(value, 1)
-    if isinstance(value, unicode):
-        value = value.encode('ascii', 'xmlcharrefreplace')
-    return value
-
-def url(v):
-    if not isinstance(v, basestring):
-        if hasattr(v, '__unicode__'):
-            v = unicode(v)
-        else:
-            v = str(v)
-    if isinstance(v, unicode):
-        v = v.encode('utf8')
-    return urllib.quote(v)
-
-def attr(**kw):
-    kw = kw.items()
-    kw.sort()
-    parts = []
-    for name, value in kw:
-        if value is None:
-            continue
-        if name.endswith('_'):
-            name = name[:-1]
-        parts.append('%s="%s"' % (html_quote(name), html_quote(value)))
-    return html(' '.join(parts))
-
-class HTMLTemplate(Template):
-
-    default_namespace = Template.default_namespace.copy()
-    default_namespace.update(dict(
-        html=html,
-        attr=attr,
-        url=url,
-        ))
-
-    def _repr(self, value, pos):
-        plain = Template._repr(self, value, pos)
-        if isinstance(value, html):
-            return plain
-        else:
-            return html_quote(plain)
-
-def sub_html(content, **kw):
-    name = kw.get('__name')
-    tmpl = HTMLTemplate(content, name=name)
-    return tmpl.substitute(kw)
-    return result
-
-
-############################################################
-## Lexing and Parsing
-############################################################
-
-def lex(s, name=None, trim_whitespace=True):
-    """
-    Lex a string into chunks:
-
-        >>> lex('hey')
-        ['hey']
-        >>> lex('hey {{you}}')
-        ['hey ', ('you', (1, 7))]
-        >>> lex('hey {{')
-        Traceback (most recent call last):
-            ...
-        TemplateError: No }} to finish last expression at line 1 column 7
-        >>> lex('hey }}')
-        Traceback (most recent call last):
-            ...
-        TemplateError: }} outside expression at line 1 column 7
-        >>> lex('hey {{ {{')
-        Traceback (most recent call last):
-            ...
-        TemplateError: {{ inside expression at line 1 column 10
-
-    """
-    in_expr = False
-    chunks = []
-    last = 0
-    last_pos = (1, 1)
-    for match in token_re.finditer(s):
-        expr = match.group(0)
-        pos = find_position(s, match.end())
-        if expr == '{{' and in_expr:
-            raise TemplateError('{{ inside expression', position=pos,
-                                name=name)
-        elif expr == '}}' and not in_expr:
-            raise TemplateError('}} outside expression', position=pos,
-                                name=name)
-        if expr == '{{':
-            part = s[last:match.start()]
-            if part:
-                chunks.append(part)
-            in_expr = True
-        else:
-            chunks.append((s[last:match.start()], last_pos))
-            in_expr = False
-        last = match.end()
-        last_pos = pos
-    if in_expr:
-        raise TemplateError('No }} to finish last expression',
-                            name=name, position=last_pos)
-    part = s[last:]
-    if part:
-        chunks.append(part)
-    if trim_whitespace:
-        chunks = trim_lex(chunks)
-    return chunks
-
-statement_re = re.compile(r'^(?:if |elif |else |for |py:)')
-single_statements = ['endif', 'endfor', 'continue', 'break']
-trail_whitespace_re = re.compile(r'\n[\t ]*$')
-lead_whitespace_re = re.compile(r'^[\t ]*\n')
-
-def trim_lex(tokens):
-    r"""
-    Takes a lexed set of tokens, and removes whitespace when there is
-    a directive on a line by itself:
-
-       >>> tokens = lex('{{if x}}\nx\n{{endif}}\ny', trim_whitespace=False)
-       >>> tokens
-       [('if x', (1, 3)), '\nx\n', ('endif', (3, 3)), '\ny']
-       >>> trim_lex(tokens)
-       [('if x', (1, 3)), 'x\n', ('endif', (3, 3)), 'y']
-    """
-    for i in range(len(tokens)):
-        current = tokens[i]
-        if isinstance(tokens[i], basestring):
-            # we don't trim this
-            continue
-        item = current[0]
-        if not statement_re.search(item) and item not in single_statements:
-            continue
-        if not i:
-            prev = ''
-        else:
-            prev = tokens[i-1]
-        if i+1 >= len(tokens):
-            next = ''
-        else:
-            next = tokens[i+1]
-        if (not isinstance(next, basestring)
-            or not isinstance(prev, basestring)):
-            continue
-        if ((not prev or trail_whitespace_re.search(prev))
-            and (not next or lead_whitespace_re.search(next))):
-            if prev:
-                m = trail_whitespace_re.search(prev)
-                # +1 to leave the leading \n on:
-                prev = prev[:m.start()+1]
-                tokens[i-1] = prev
-            if next:
-                m = lead_whitespace_re.search(next)
-                next = next[m.end():]
-                tokens[i+1] = next
-    return tokens
-        
-
-def find_position(string, index):
-    """Given a string and index, return (line, column)"""
-    leading = string[:index].splitlines()
-    return (len(leading), len(leading[-1])+1)
-
-def parse(s, name=None):
-    r"""
-    Parses a string into a kind of AST
-
-        >>> parse('{{x}}')
-        [('expr', (1, 3), 'x')]
-        >>> parse('foo')
-        ['foo']
-        >>> parse('{{if x}}test{{endif}}')
-        [('cond', (1, 3), ('if', (1, 3), 'x', ['test']))]
-        >>> parse('series->{{for x in y}}x={{x}}{{endfor}}')
-        ['series->', ('for', (1, 11), ('x',), 'y', ['x=', ('expr', (1, 27), 'x')])]
-        >>> parse('{{for x, y in z:}}{{continue}}{{endfor}}')
-        [('for', (1, 3), ('x', 'y'), 'z', [('continue', (1, 21))])]
-        >>> parse('{{py:x=1}}')
-        [('py', (1, 3), 'x=1')]
-        >>> parse('{{if x}}a{{elif y}}b{{else}}c{{endif}}')
-        [('cond', (1, 3), ('if', (1, 3), 'x', ['a']), ('elif', (1, 12), 'y', ['b']), ('else', (1, 23), None, ['c']))]
-
-    Some exceptions::
-        
-        >>> parse('{{continue}}')
-        Traceback (most recent call last):
-            ...
-        TemplateError: continue outside of for loop at line 1 column 3
-        >>> parse('{{if x}}foo')
-        Traceback (most recent call last):
-            ...
-        TemplateError: No {{endif}} at line 1 column 3
-        >>> parse('{{else}}')
-        Traceback (most recent call last):
-            ...
-        TemplateError: else outside of an if block at line 1 column 3
-        >>> parse('{{if x}}{{for x in y}}{{endif}}{{endfor}}')
-        Traceback (most recent call last):
-            ...
-        TemplateError: Unexpected endif at line 1 column 25
-        >>> parse('{{if}}{{endif}}')
-        Traceback (most recent call last):
-            ...
-        TemplateError: if with no expression at line 1 column 3
-        >>> parse('{{for x y}}{{endfor}}')
-        Traceback (most recent call last):
-            ...
-        TemplateError: Bad for (no "in") in 'x y' at line 1 column 3
-        >>> parse('{{py:x=1\ny=2}}')
-        Traceback (most recent call last):
-            ...
-        TemplateError: Multi-line py blocks must start with a newline at line 1 column 3
-    """
-    tokens = lex(s, name=name)
-    result = []
-    while tokens:
-        next, tokens = parse_expr(tokens, name)
-        result.append(next)
-    return result
-
-def parse_expr(tokens, name, context=()):
-    if isinstance(tokens[0], basestring):
-        return tokens[0], tokens[1:]
-    expr, pos = tokens[0]
-    expr = expr.strip()
-    if expr.startswith('py:'):
-        expr = expr[3:].lstrip(' \t')
-        if expr.startswith('\n'):
-            expr = expr[1:]
-        else:
-            if '\n' in expr:
-                raise TemplateError(
-                    'Multi-line py blocks must start with a newline',
-                    position=pos, name=name)
-        return ('py', pos, expr), tokens[1:]
-    elif expr in ('continue', 'break'):
-        if 'for' not in context:
-            raise TemplateError(
-                'continue outside of for loop',
-                position=pos, name=name)
-        return (expr, pos), tokens[1:]
-    elif expr.startswith('if '):
-        return parse_cond(tokens, name, context)
-    elif (expr.startswith('elif ')
-          or expr == 'else'):
-        raise TemplateError(
-            '%s outside of an if block' % expr.split()[0],
-            position=pos, name=name)
-    elif expr in ('if', 'elif', 'for'):
-        raise TemplateError(
-            '%s with no expression' % expr,
-            position=pos, name=name)
-    elif expr in ('endif', 'endfor'):
-        raise TemplateError(
-            'Unexpected %s' % expr,
-            position=pos, name=name)
-    elif expr.startswith('for '):
-        return parse_for(tokens, name, context)
-    elif expr.startswith('default '):
-        return parse_default(tokens, name, context)
-    elif expr.startswith('#'):
-        return ('comment', pos, tokens[0][0]), tokens[1:]
-    return ('expr', pos, tokens[0][0]), tokens[1:]
-
-def parse_cond(tokens, name, context):
-    start = tokens[0][1]
-    pieces = []
-    context = context + ('if',)
-    while 1:
-        if not tokens:
-            raise TemplateError(
-                'Missing {{endif}}',
-                position=start, name=name)
-        if (isinstance(tokens[0], tuple)
-            and tokens[0][0] == 'endif'):
-            return ('cond', start) + tuple(pieces), tokens[1:]
-        next, tokens = parse_one_cond(tokens, name, context)
-        pieces.append(next)
-
-def parse_one_cond(tokens, name, context):
-    (first, pos), tokens = tokens[0], tokens[1:]
-    content = []
-    if first.endswith(':'):
-        first = first[:-1]
-    if first.startswith('if '):
-        part = ('if', pos, first[3:].lstrip(), content)
-    elif first.startswith('elif '):
-        part = ('elif', pos, first[5:].lstrip(), content)
-    elif first == 'else':
-        part = ('else', pos, None, content)
-    else:
-        assert 0, "Unexpected token %r at %s" % (first, pos)
-    while 1:
-        if not tokens:
-            raise TemplateError(
-                'No {{endif}}',
-                position=pos, name=name)
-        if (isinstance(tokens[0], tuple)
-            and (tokens[0][0] == 'endif'
-                 or tokens[0][0].startswith('elif ')
-                 or tokens[0][0] == 'else')):
-            return part, tokens
-        next, tokens = parse_expr(tokens, name, context)
-        content.append(next)
-        
-def parse_for(tokens, name, context):
-    first, pos = tokens[0]
-    tokens = tokens[1:]
-    context = ('for',) + context
-    content = []
-    assert first.startswith('for ')
-    if first.endswith(':'):
-        first = first[:-1]
-    first = first[3:].strip()
-    match = in_re.search(first)
-    if not match:
-        raise TemplateError(
-            'Bad for (no "in") in %r' % first,
-            position=pos, name=name)
-    vars = first[:match.start()]
-    if '(' in vars:
-        raise TemplateError(
-            'You cannot have () in the variable section of a for loop (%r)'
-            % vars, position=pos, name=name)
-    vars = tuple([
-        v.strip() for v in first[:match.start()].split(',')
-        if v.strip()])
-    expr = first[match.end():]
-    while 1:
-        if not tokens:
-            raise TemplateError(
-                'No {{endfor}}',
-                position=pos, name=name)
-        if (isinstance(tokens[0], tuple)
-            and tokens[0][0] == 'endfor'):
-            return ('for', pos, vars, expr, content), tokens[1:]
-        next, tokens = parse_expr(tokens, name, context)
-        content.append(next)
-
-def parse_default(tokens, name, context):
-    first, pos = tokens[0]
-    assert first.startswith('default ')
-    first = first.split(None, 1)[1]
-    parts = first.split('=', 1)
-    if len(parts) == 1:
-        raise TemplateError(
-            "Expression must be {{default var=value}}; no = found in %r" % first,
-            position=pos, name=name)
-    var = parts[0].strip()
-    if ',' in var:
-        raise TemplateError(
-            "{{default x, y = ...}} is not supported",
-            position=pos, name=name)
-    if not var_re.search(var):
-        raise TemplateError(
-            "Not a valid variable name for {{default}}: %r"
-            % var, position=pos, name=name)
-    expr = parts[1].strip()
-    return ('default', pos, var, expr), tokens[1:]
-
-_fill_command_usage = """\
-%prog [OPTIONS] TEMPLATE arg=value
-
-Use py:arg=value to set a Python value; otherwise all values are
-strings.
-"""
-
-def fill_command(args=None):
-    import sys, optparse, pkg_resources, os
-    if args is None:
-        args = sys.argv[1:]
-    dist = pkg_resources.get_distribution('Paste')
-    parser = optparse.OptionParser(
-        version=str(dist),
-        usage=_fill_command_usage)
-    parser.add_option(
-        '-o', '--output',
-        dest='output',
-        metavar="FILENAME",
-        help="File to write output to (default stdout)")
-    parser.add_option(
-        '--html',
-        dest='use_html',
-        action='store_true',
-        help="Use HTML style filling (including automatic HTML quoting)")
-    parser.add_option(
-        '--env',
-        dest='use_env',
-        action='store_true',
-        help="Put the environment in as top-level variables")
-    options, args = parser.parse_args(args)
-    if len(args) < 1:
-        print 'You must give a template filename'
-        print dir(parser)
-        assert 0
-    template_name = args[0]
-    args = args[1:]
-    vars = {}
-    if options.use_env:
-        vars.update(os.environ)
-    for value in args:
-        if '=' not in value:
-            print 'Bad argument: %r' % value
-            sys.exit(2)
-        name, value = value.split('=', 1)
-        if name.startswith('py:'):
-            name = name[:3]
-            value = eval(value)
-        vars[name] = value
-    if template_name == '-':
-        template_content = sys.stdin.read()
-        template_name = '<stdin>'
-    else:
-        f = open(template_name, 'rb')
-        template_content = f.read()
-        f.close()
-    if options.use_html:
-        TemplateClass = HTMLTemplate
-    else:
-        TemplateClass = Template
-    template = TemplateClass(template_content, name=template_name)
-    result = template.substitute(vars)
-    if options.output:
-        f = open(options.output, 'wb')
-        f.write(result)
-        f.close()
-    else:
-        sys.stdout.write(result)
-
-if __name__ == '__main__':
-    from paste.util.template import fill_command
-    fill_command()
-        
-    
diff --git a/lib/paste/util/threadedprint.py b/lib/paste/util/threadedprint.py
@@ -1,250 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-"""
-threadedprint.py
-================
-
-:author: Ian Bicking
-:date: 12 Jul 2004
-
-Multi-threaded printing; allows the output produced via print to be
-separated according to the thread.
-
-To use this, you must install the catcher, like::
-
-    threadedprint.install()
-
-The installation optionally takes one of three parameters:
-
-default
-    The default destination for print statements (e.g., ``sys.stdout``).
-factory
-    A function that will produce the stream for a thread, given the
-    thread's name.
-paramwriter
-    Instead of writing to a file-like stream, this function will be
-    called like ``paramwriter(thread_name, text)`` for every write.
-
-The thread name is the value returned by
-``threading.currentThread().getName()``, a string (typically something
-like Thread-N).
-
-You can also submit file-like objects for specific threads, which will
-override any of these parameters.  To do this, call ``register(stream,
-[threadName])``.  ``threadName`` is optional, and if not provided the
-stream will be registered for the current thread.
-
-If no specific stream is registered for a thread, and no default has
-been provided, then an error will occur when anything is written to
-``sys.stdout`` (or printed).
-
-Note: the stream's ``write`` method will be called in the thread the
-text came from, so you should consider thread safety, especially if
-multiple threads share the same writer.
-
-Note: if you want access to the original standard out, use
-``sys.__stdout__``.
-
-You may also uninstall this, via::
-
-    threadedprint.uninstall()
-
-TODO
-----
-
-* Something with ``sys.stderr``.
-* Some default handlers.  Maybe something that hooks into `logging`.
-* Possibly cache the results of ``factory`` calls.  This would be a
-  semantic change.
-
-"""
-
-import threading
-import sys
-from paste.util import filemixin
-
-class PrintCatcher(filemixin.FileMixin):
-
-    def __init__(self, default=None, factory=None, paramwriter=None,
-                 leave_stdout=False):
-        assert len(filter(lambda x: x is not None,
-                          [default, factory, paramwriter])) <= 1, (
-            "You can only provide one of default, factory, or paramwriter")
-        if leave_stdout:
-            assert not default, (
-                "You cannot pass in both default (%r) and "
-                "leave_stdout=True" % default)
-            default = sys.stdout
-        if default:
-            self._defaultfunc = self._writedefault
-        elif factory:
-            self._defaultfunc = self._writefactory
-        elif paramwriter:
-            self._defaultfunc = self._writeparam
-        else:
-            self._defaultfunc = self._writeerror
-        self._default = default
-        self._factory = factory
-        self._paramwriter = paramwriter
-        self._catchers = {}
-
-    def write(self, v, currentThread=threading.currentThread):
-        name = currentThread().getName()
-        catchers = self._catchers
-        if not catchers.has_key(name):
-            self._defaultfunc(name, v)
-        else:
-            catcher = catchers[name]
-            catcher.write(v)
-
-    def seek(self, *args):
-        # Weird, but Google App Engine is seeking on stdout
-        name = threading.currentThread().getName()
-        catchers = self._catchers
-        if not name in catchers:
-            self._default.seek(*args)
-        else:
-            catchers[name].seek(*args)
-
-    def read(self, *args):
-        name = threading.currentThread().getName()
-        catchers = self._catchers
-        if not name in catchers:
-            self._default.read(*args)
-        else:
-            catchers[name].read(*args)
-        
-
-    def _writedefault(self, name, v):
-        self._default.write(v)
-
-    def _writefactory(self, name, v):
-        self._factory(name).write(v)
-
-    def _writeparam(self, name, v):
-        self._paramwriter(name, v)
-
-    def _writeerror(self, name, v):
-        assert False, (
-            "There is no PrintCatcher output stream for the thread %r"
-            % name)
-
-    def register(self, catcher, name=None,
-                 currentThread=threading.currentThread):
-        if name is None:
-            name = currentThread().getName()
-        self._catchers[name] = catcher
-
-    def deregister(self, name=None,
-                   currentThread=threading.currentThread):
-        if name is None:
-            name = currentThread().getName()
-        assert self._catchers.has_key(name), (
-            "There is no PrintCatcher catcher for the thread %r" % name)
-        del self._catchers[name]
-
-_printcatcher = None
-_oldstdout = None
-
-def install(**kw):
-    global _printcatcher, _oldstdout, register, deregister
-    if (not _printcatcher or sys.stdout is not _printcatcher):
-        _oldstdout = sys.stdout
-        _printcatcher = sys.stdout = PrintCatcher(**kw)
-        register = _printcatcher.register
-        deregister = _printcatcher.deregister
-
-def uninstall():
-    global _printcatcher, _oldstdout, register, deregister
-    if _printcatcher:
-        sys.stdout = _oldstdout
-        _printcatcher = _oldstdout = None
-        register = not_installed_error
-        deregister = not_installed_error
-
-def not_installed_error(*args, **kw):
-    assert False, (
-        "threadedprint has not yet been installed (call "
-        "threadedprint.install())")
-
-register = deregister = not_installed_error
-
-class StdinCatcher(filemixin.FileMixin):
-
-    def __init__(self, default=None, factory=None, paramwriter=None):
-        assert len(filter(lambda x: x is not None,
-                          [default, factory, paramwriter])) <= 1, (
-            "You can only provide one of default, factory, or paramwriter")
-        if default:
-            self._defaultfunc = self._readdefault
-        elif factory:
-            self._defaultfunc = self._readfactory
-        elif paramwriter:
-            self._defaultfunc = self._readparam
-        else:
-            self._defaultfunc = self._readerror
-        self._default = default
-        self._factory = factory
-        self._paramwriter = paramwriter
-        self._catchers = {}
-
-    def read(self, size=None, currentThread=threading.currentThread):
-        name = currentThread().getName()
-        catchers = self._catchers
-        if not catchers.has_key(name):
-            return self._defaultfunc(name, size)
-        else:
-            catcher = catchers[name]
-            return catcher.read(size)
-
-    def _readdefault(self, name, size):
-        self._default.read(size)
-
-    def _readfactory(self, name, size):
-        self._factory(name).read(size)
-
-    def _readparam(self, name, size):
-        self._paramreader(name, size)
-
-    def _readerror(self, name, size):
-        assert False, (
-            "There is no StdinCatcher output stream for the thread %r"
-            % name)
-
-    def register(self, catcher, name=None,
-                 currentThread=threading.currentThread):
-        if name is None:
-            name = currentThread().getName()
-        self._catchers[name] = catcher
-
-    def deregister(self, catcher, name=None,
-                   currentThread=threading.currentThread):
-        if name is None:
-            name = currentThread().getName()
-        assert self._catchers.has_key(name), (
-            "There is no StdinCatcher catcher for the thread %r" % name)
-        del self._catchers[name]
-
-_stdincatcher = None
-_oldstdin = None
-
-def install_stdin(**kw):
-    global _stdincatcher, _oldstdin, register_stdin, deregister_stdin
-    if not _stdincatcher:
-        _oldstdin = sys.stdin
-        _stdincatcher = sys.stdin = StdinCatcher(**kw)
-        register_stdin = _stdincatcher.register
-        deregister_stdin = _stdincatcher.deregister
-
-def uninstall():
-    global _stdincatcher, _oldstin, register_stdin, deregister_stdin
-    if _stdincatcher:
-        sys.stdin = _oldstdin
-        _stdincatcher = _oldstdin = None
-        register_stdin = deregister_stdin = not_installed_error_stdin
-
-def not_installed_error_stdin(*args, **kw):
-    assert False, (
-        "threadedprint has not yet been installed for stdin (call "
-        "threadedprint.install_stdin())")
diff --git a/lib/paste/util/threadinglocal.py b/lib/paste/util/threadinglocal.py
@@ -1,43 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-Implementation of thread-local storage, for Python versions that don't
-have thread local storage natively.
-"""
-
-try:
-    import threading
-except ImportError:
-    # No threads, so "thread local" means process-global
-    class local(object):
-        pass
-else:
-    try:
-        local = threading.local
-    except AttributeError:
-        # Added in 2.4, but now we'll have to define it ourselves
-        import thread
-        class local(object):
-
-            def __init__(self):
-                self.__dict__['__objs'] = {}
-
-            def __getattr__(self, attr, g=thread.get_ident):
-                try:
-                    return self.__dict__['__objs'][g()][attr]
-                except KeyError:
-                    raise AttributeError(
-                        "No variable %s defined for the thread %s"
-                        % (attr, g()))
-
-            def __setattr__(self, attr, value, g=thread.get_ident):
-                self.__dict__['__objs'].setdefault(g(), {})[attr] = value
-
-            def __delattr__(self, attr, g=thread.get_ident):
-                try:
-                    del self.__dict__['__objs'][g()][attr]
-                except KeyError:
-                    raise AttributeError(
-                        "No variable %s defined for thread %s"
-                        % (attr, g()))
-
diff --git a/lib/paste/wsgilib.py b/lib/paste/wsgilib.py
@@ -1,597 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
-"""
-A module of many disparate routines.
-"""
-
-# functions which moved to paste.request and paste.response
-# Deprecated around 15 Dec 2005
-from paste.request import get_cookies, parse_querystring, parse_formvars
-from paste.request import construct_url, path_info_split, path_info_pop
-from paste.response import HeaderDict, has_header, header_value, remove_header
-from paste.response import error_body_response, error_response, error_response_app
-
-from traceback import print_exception
-import urllib
-from cStringIO import StringIO
-import sys
-from urlparse import urlsplit
-import warnings
-
-__all__ = ['add_close', 'add_start_close', 'capture_output', 'catch_errors',
-           'catch_errors_app', 'chained_app_iters', 'construct_url',
-           'dump_environ', 'encode_unicode_app_iter', 'error_body_response',
-           'error_response', 'get_cookies', 'has_header', 'header_value',
-           'interactive', 'intercept_output', 'path_info_pop',
-           'path_info_split', 'raw_interactive', 'send_file']
-
-class add_close(object):
-    """
-    An an iterable that iterates over app_iter, then calls
-    close_func.
-    """
-
-    def __init__(self, app_iterable, close_func):
-        self.app_iterable = app_iterable
-        self.app_iter = iter(app_iterable)
-        self.close_func = close_func
-        self._closed = False
-
-    def __iter__(self):
-        return self
-
-    def next(self):
-        return self.app_iter.next()
-
-    def close(self):
-        self._closed = True
-        if hasattr(self.app_iterable, 'close'):
-            self.app_iterable.close()
-        self.close_func()
-
-    def __del__(self):
-        if not self._closed:
-            # We can't raise an error or anything at this stage
-            print >> sys.stderr, (
-                "Error: app_iter.close() was not called when finishing "
-                "WSGI request. finalization function %s not called"
-                % self.close_func)
-
-class add_start_close(object):
-    """
-    An an iterable that iterates over app_iter, calls start_func
-    before the first item is returned, then calls close_func at the
-    end.
-    """
-
-    def __init__(self, app_iterable, start_func, close_func=None):
-        self.app_iterable = app_iterable
-        self.app_iter = iter(app_iterable)
-        self.first = True
-        self.start_func = start_func
-        self.close_func = close_func
-        self._closed = False
-
-    def __iter__(self):
-        return self
-
-    def next(self):
-        if self.first:
-            self.start_func()
-            self.first = False
-        return self.app_iter.next()
-
-    def close(self):
-        self._closed = True
-        if hasattr(self.app_iterable, 'close'):
-            self.app_iterable.close()
-        if self.close_func is not None:
-            self.close_func()
-
-    def __del__(self):
-        if not self._closed:
-            # We can't raise an error or anything at this stage
-            print >> sys.stderr, (
-                "Error: app_iter.close() was not called when finishing "
-                "WSGI request. finalization function %s not called"
-                % self.close_func)
-
-class chained_app_iters(object):
-
-    """
-    Chains several app_iters together, also delegating .close() to each
-    of them.
-    """
-
-    def __init__(self, *chained):
-        self.app_iters = chained
-        self.chained = [iter(item) for item in chained]
-        self._closed = False
-
-    def __iter__(self):
-        return self
-
-    def next(self):
-        if len(self.chained) == 1:
-            return self.chained[0].next()
-        else:
-            try:
-                return self.chained[0].next()
-            except StopIteration:
-                self.chained.pop(0)
-                return self.next()
-
-    def close(self):
-        self._closed = True
-        got_exc = None
-        for app_iter in self.app_iters:
-            try:
-                if hasattr(app_iter, 'close'):
-                    app_iter.close()
-            except:
-                got_exc = sys.exc_info()
-        if got_exc:
-            raise got_exc[0], got_exc[1], got_exc[2]
-
-    def __del__(self):
-        if not self._closed:
-            # We can't raise an error or anything at this stage
-            print >> sys.stderr, (
-                "Error: app_iter.close() was not called when finishing "
-                "WSGI request. finalization function %s not called"
-                % self.close_func)
-
-class encode_unicode_app_iter(object):
-    """
-    Encodes an app_iterable's unicode responses as strings
-    """
-
-    def __init__(self, app_iterable, encoding=sys.getdefaultencoding(),
-                 errors='strict'):
-        self.app_iterable = app_iterable
-        self.app_iter = iter(app_iterable)
-        self.encoding = encoding
-        self.errors = errors
-
-    def __iter__(self):
-        return self
-
-    def next(self):
-        content = self.app_iter.next()
-        if isinstance(content, unicode):
-            content = content.encode(self.encoding, self.errors)
-        return content
-
-    def close(self):
-        if hasattr(self.app_iterable, 'close'):
-            self.app_iterable.close()
-
-def catch_errors(application, environ, start_response, error_callback,
-                 ok_callback=None):
-    """
-    Runs the application, and returns the application iterator (which should be
-    passed upstream).  If an error occurs then error_callback will be called with
-    exc_info as its sole argument.  If no errors occur and ok_callback is given,
-    then it will be called with no arguments.
-    """
-    try:
-        app_iter = application(environ, start_response)
-    except:
-        error_callback(sys.exc_info())
-        raise
-    if type(app_iter) in (list, tuple):
-        # These won't produce exceptions
-        if ok_callback:
-            ok_callback()
-        return app_iter
-    else:
-        return _wrap_app_iter(app_iter, error_callback, ok_callback)
-
-class _wrap_app_iter(object):
-
-    def __init__(self, app_iterable, error_callback, ok_callback):
-        self.app_iterable = app_iterable
-        self.app_iter = iter(app_iterable)
-        self.error_callback = error_callback
-        self.ok_callback = ok_callback
-        if hasattr(self.app_iterable, 'close'):
-            self.close = self.app_iterable.close
-
-    def __iter__(self):
-        return self
-
-    def next(self):
-        try:
-            return self.app_iter.next()
-        except StopIteration:
-            if self.ok_callback:
-                self.ok_callback()
-            raise
-        except:
-            self.error_callback(sys.exc_info())
-            raise
-
-def catch_errors_app(application, environ, start_response, error_callback_app,
-                     ok_callback=None, catch=Exception):
-    """
-    Like ``catch_errors``, except error_callback_app should be a
-    callable that will receive *three* arguments -- ``environ``,
-    ``start_response``, and ``exc_info``.  It should call
-    ``start_response`` (*with* the exc_info argument!) and return an
-    iterator.
-    """
-    try:
-        app_iter = application(environ, start_response)
-    except catch:
-        return error_callback_app(environ, start_response, sys.exc_info())
-    if type(app_iter) in (list, tuple):
-        # These won't produce exceptions
-        if ok_callback is not None:
-            ok_callback()
-        return app_iter
-    else:
-        return _wrap_app_iter_app(
-            environ, start_response, app_iter,
-            error_callback_app, ok_callback, catch=catch)
-
-class _wrap_app_iter_app(object):
-
-    def __init__(self, environ, start_response, app_iterable,
-                 error_callback_app, ok_callback, catch=Exception):
-        self.environ = environ
-        self.start_response = start_response
-        self.app_iterable = app_iterable
-        self.app_iter = iter(app_iterable)
-        self.error_callback_app = error_callback_app
-        self.ok_callback = ok_callback
-        self.catch = catch
-        if hasattr(self.app_iterable, 'close'):
-            self.close = self.app_iterable.close
-
-    def __iter__(self):
-        return self
-
-    def next(self):
-        try:
-            return self.app_iter.next()
-        except StopIteration:
-            if self.ok_callback:
-                self.ok_callback()
-            raise
-        except self.catch:
-            if hasattr(self.app_iterable, 'close'):
-                try:
-                    self.app_iterable.close()
-                except:
-                    # @@: Print to wsgi.errors?
-                    pass
-            new_app_iterable = self.error_callback_app(
-                self.environ, self.start_response, sys.exc_info())
-            app_iter = iter(new_app_iterable)
-            if hasattr(new_app_iterable, 'close'):
-                self.close = new_app_iterable.close
-            self.next = app_iter.next
-            return self.next()
-
-def raw_interactive(application, path='', raise_on_wsgi_error=False,
-                    **environ):
-    """
-    Runs the application in a fake environment.
-    """
-    assert "path_info" not in environ, "argument list changed"
-    if raise_on_wsgi_error:
-        errors = ErrorRaiser()
-    else:
-        errors = StringIO()
-    basic_environ = {
-        # mandatory CGI variables
-        'REQUEST_METHOD': 'GET',     # always mandatory
-        'SCRIPT_NAME': '',           # may be empty if app is at the root
-        'PATH_INFO': '',             # may be empty if at root of app
-        'SERVER_NAME': 'localhost',  # always mandatory
-        'SERVER_PORT': '80',         # always mandatory 
-        'SERVER_PROTOCOL': 'HTTP/1.0',
-        # mandatory wsgi variables
-        'wsgi.version': (1, 0),
-        'wsgi.url_scheme': 'http',
-        'wsgi.input': StringIO(''),
-        'wsgi.errors': errors,
-        'wsgi.multithread': False,
-        'wsgi.multiprocess': False,
-        'wsgi.run_once': False,
-        }
-    if path:
-        (_, _, path_info, query, fragment) = urlsplit(str(path))
-        path_info = urllib.unquote(path_info)
-        # urlsplit returns unicode so coerce it back to str
-        path_info, query = str(path_info), str(query)
-        basic_environ['PATH_INFO'] = path_info
-        if query:
-            basic_environ['QUERY_STRING'] = query
-    for name, value in environ.items():
-        name = name.replace('__', '.')
-        basic_environ[name] = value
-    if ('SERVER_NAME' in basic_environ
-        and 'HTTP_HOST' not in basic_environ):
-        basic_environ['HTTP_HOST'] = basic_environ['SERVER_NAME']
-    istream = basic_environ['wsgi.input']
-    if isinstance(istream, str):
-        basic_environ['wsgi.input'] = StringIO(istream)
-        basic_environ['CONTENT_LENGTH'] = len(istream)
-    data = {}
-    output = []
-    headers_set = []
-    headers_sent = []
-    def start_response(status, headers, exc_info=None):
-        if exc_info:
-            try:
-                if headers_sent:
-                    # Re-raise original exception only if headers sent
-                    raise exc_info[0], exc_info[1], exc_info[2]
-            finally:
-                # avoid dangling circular reference
-                exc_info = None
-        elif headers_set:
-            # You cannot set the headers more than once, unless the
-            # exc_info is provided.
-            raise AssertionError("Headers already set and no exc_info!")
-        headers_set.append(True)
-        data['status'] = status
-        data['headers'] = headers
-        return output.append
-    app_iter = application(basic_environ, start_response)
-    try:
-        try:
-            for s in app_iter:
-                if not isinstance(s, str):
-                    raise ValueError(
-                        "The app_iter response can only contain str (not "
-                        "unicode); got: %r" % s)
-                headers_sent.append(True)
-                if not headers_set:
-                    raise AssertionError("Content sent w/o headers!")
-                output.append(s)
-        except TypeError, e:
-            # Typically "iteration over non-sequence", so we want
-            # to give better debugging information...
-            e.args = ((e.args[0] + ' iterable: %r' % app_iter),) + e.args[1:]
-            raise
-    finally:
-        if hasattr(app_iter, 'close'):
-            app_iter.close()
-    return (data['status'], data['headers'], ''.join(output),
-            errors.getvalue())
-
-class ErrorRaiser(object):
-
-    def flush(self):
-        pass
-
-    def write(self, value):
-        if not value:
-            return
-        raise AssertionError(
-            "No errors should be written (got: %r)" % value)
-
-    def writelines(self, seq):
-        raise AssertionError(
-            "No errors should be written (got lines: %s)" % list(seq))
-
-    def getvalue(self):
-        return ''
-
-def interactive(*args, **kw):
-    """
-    Runs the application interatively, wrapping `raw_interactive` but
-    returning the output in a formatted way.
-    """
-    status, headers, content, errors = raw_interactive(*args, **kw)
-    full = StringIO()
-    if errors:
-        full.write('Errors:\n')
-        full.write(errors.strip())
-        full.write('\n----------end errors\n')
-    full.write(status + '\n')
-    for name, value in headers:
-        full.write('%s: %s\n' % (name, value))
-    full.write('\n')
-    full.write(content)
-    return full.getvalue()
-interactive.proxy = 'raw_interactive'
-
-def dump_environ(environ, start_response):
-    """
-    Application which simply dumps the current environment
-    variables out as a plain text response.
-    """
-    output = []
-    keys = environ.keys()
-    keys.sort()
-    for k in keys:
-        v = str(environ[k]).replace("\n","\n    ")
-        output.append("%s: %s\n" % (k, v))
-    output.append("\n")
-    content_length = environ.get("CONTENT_LENGTH", '')
-    if content_length:
-        output.append(environ['wsgi.input'].read(int(content_length)))
-        output.append("\n")
-    output = "".join(output)
-    headers = [('Content-Type', 'text/plain'),
-               ('Content-Length', str(len(output)))]
-    start_response("200 OK", headers)
-    return [output]
-
-def send_file(filename):
-    warnings.warn(
-        "wsgilib.send_file has been moved to paste.fileapp.FileApp",
-        DeprecationWarning, 2)
-    from paste import fileapp
-    return fileapp.FileApp(filename)
-
-def capture_output(environ, start_response, application):
-    """
-    Runs application with environ and start_response, and captures
-    status, headers, and body.
-
-    Sends status and header, but *not* body.  Returns (status,
-    headers, body).  Typically this is used like:
-    
-    .. code-block:: python
-
-        def dehtmlifying_middleware(application):
-            def replacement_app(environ, start_response):
-                status, headers, body = capture_output(
-                    environ, start_response, application)
-                content_type = header_value(headers, 'content-type')
-                if (not content_type
-                    or not content_type.startswith('text/html')):
-                    return [body]
-                body = re.sub(r'<.*?>', '', body)
-                return [body]
-            return replacement_app
-
-    """
-    warnings.warn(
-        'wsgilib.capture_output has been deprecated in favor '
-        'of wsgilib.intercept_output',
-        DeprecationWarning, 2)
-    data = []
-    output = StringIO()
-    def replacement_start_response(status, headers, exc_info=None):
-        if data:
-            data[:] = []
-        data.append(status)
-        data.append(headers)
-        start_response(status, headers, exc_info)
-        return output.write
-    app_iter = application(environ, replacement_start_response)
-    try:
-        for item in app_iter:
-            output.write(item)
-    finally:
-        if hasattr(app_iter, 'close'):
-            app_iter.close()
-    if not data:
-        data.append(None)
-    if len(data) < 2:
-        data.append(None)
-    data.append(output.getvalue())
-    return data
-
-def intercept_output(environ, application, conditional=None,
-                     start_response=None):
-    """
-    Runs application with environ and captures status, headers, and
-    body.  None are sent on; you must send them on yourself (unlike
-    ``capture_output``)
-
-    Typically this is used like:
-    
-    .. code-block:: python
-
-        def dehtmlifying_middleware(application):
-            def replacement_app(environ, start_response):
-                status, headers, body = intercept_output(
-                    environ, application)
-                start_response(status, headers)
-                content_type = header_value(headers, 'content-type')
-                if (not content_type
-                    or not content_type.startswith('text/html')):
-                    return [body]
-                body = re.sub(r'<.*?>', '', body)
-                return [body]
-            return replacement_app
-
-    A third optional argument ``conditional`` should be a function
-    that takes ``conditional(status, headers)`` and returns False if
-    the request should not be intercepted.  In that case
-    ``start_response`` will be called and ``(None, None, app_iter)``
-    will be returned.  You must detect that in your code and return
-    the app_iter, like:
-    
-    .. code-block:: python
-
-        def dehtmlifying_middleware(application):
-            def replacement_app(environ, start_response):
-                status, headers, body = intercept_output(
-                    environ, application,
-                    lambda s, h: header_value(headers, 'content-type').startswith('text/html'),
-                    start_response)
-                if status is None:
-                    return body
-                start_response(status, headers)
-                body = re.sub(r'<.*?>', '', body)
-                return [body]
-            return replacement_app
-    """
-    if conditional is not None and start_response is None:
-        raise TypeError(
-            "If you provide conditional you must also provide "
-            "start_response")
-    data = []
-    output = StringIO()
-    def replacement_start_response(status, headers, exc_info=None):
-        if conditional is not None and not conditional(status, headers):
-            data.append(None)
-            return start_response(status, headers, exc_info)
-        if data:
-            data[:] = []
-        data.append(status)
-        data.append(headers)
-        return output.write
-    app_iter = application(environ, replacement_start_response)
-    if data[0] is None:
-        return (None, None, app_iter)
-    try:
-        for item in app_iter:
-            output.write(item)
-    finally:
-        if hasattr(app_iter, 'close'):
-            app_iter.close()
-    if not data:
-        data.append(None)
-    if len(data) < 2:
-        data.append(None)
-    data.append(output.getvalue())
-    return data
-
-## Deprecation warning wrapper:
-
-class ResponseHeaderDict(HeaderDict):
-
-    def __init__(self, *args, **kw):
-        warnings.warn(
-            "The class wsgilib.ResponseHeaderDict has been moved "
-            "to paste.response.HeaderDict",
-            DeprecationWarning, 2)
-        HeaderDict.__init__(self, *args, **kw)
-
-def _warn_deprecated(new_func):
-    new_name = new_func.func_name
-    new_path = new_func.func_globals['__name__'] + '.' + new_name
-    def replacement(*args, **kw):
-        warnings.warn(
-            "The function wsgilib.%s has been moved to %s"
-            % (new_name, new_path),
-            DeprecationWarning, 2)
-        return new_func(*args, **kw)
-    try:
-        replacement.func_name = new_func.func_name
-    except:
-        pass
-    return replacement
-
-# Put warnings wrapper in place for all public functions that
-# were imported from elsewhere:
-
-for _name in __all__:
-    _func = globals()[_name]
-    if (hasattr(_func, 'func_globals')
-        and _func.func_globals['__name__'] != __name__):
-        globals()[_name] = _warn_deprecated(_func)
-
-if __name__ == '__main__':
-    import doctest
-    doctest.testmod()
-    
diff --git a/lib/paste/wsgiwrappers.py b/lib/paste/wsgiwrappers.py
@@ -1,581 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""WSGI Wrappers for a Request and Response
-
-The WSGIRequest and WSGIResponse objects are light wrappers to make it easier
-to deal with an incoming request and sending a response.
-"""
-import re
-import warnings
-from pprint import pformat
-from Cookie import SimpleCookie
-from paste.request import EnvironHeaders, get_cookie_dict, \
-    parse_dict_querystring, parse_formvars
-from paste.util.multidict import MultiDict, UnicodeMultiDict
-from paste.registry import StackedObjectProxy
-from paste.response import HeaderDict
-from paste.wsgilib import encode_unicode_app_iter
-from paste.httpheaders import ACCEPT_LANGUAGE
-from paste.util.mimeparse import desired_matches
-
-__all__ = ['WSGIRequest', 'WSGIResponse']
-
-_CHARSET_RE = re.compile(r';\s*charset=([^;]*)', re.I)
-
-class DeprecatedSettings(StackedObjectProxy):
-    def _push_object(self, obj):
-        warnings.warn('paste.wsgiwrappers.settings is deprecated: Please use '
-                      'paste.wsgiwrappers.WSGIRequest.defaults instead',
-                      DeprecationWarning, 3)
-        WSGIResponse.defaults._push_object(obj)
-        StackedObjectProxy._push_object(self, obj)
-
-# settings is deprecated: use WSGIResponse.defaults instead
-settings = DeprecatedSettings(default=dict())
-
-class environ_getter(object):
-    """For delegating an attribute to a key in self.environ."""
-    # @@: Also __set__?  Should setting be allowed?
-    def __init__(self, key, default='', default_factory=None):
-        self.key = key
-        self.default = default
-        self.default_factory = default_factory
-    def __get__(self, obj, type=None):
-        if type is None:
-            return self
-        if self.key not in obj.environ:
-            if self.default_factory:
-                val = obj.environ[self.key] = self.default_factory()
-                return val
-            else:
-                return self.default
-        return obj.environ[self.key]
-
-    def __repr__(self):
-        return '<Proxy for WSGI environ %r key>' % self.key
-
-class WSGIRequest(object):
-    """WSGI Request API Object
-
-    This object represents a WSGI request with a more friendly interface.
-    This does not expose every detail of the WSGI environment, and attempts
-    to express nothing beyond what is available in the environment
-    dictionary.
-
-    The only state maintained in this object is the desired ``charset``,
-    its associated ``errors`` handler, and the ``decode_param_names``
-    option.
-
-    The incoming parameter values will be automatically coerced to unicode
-    objects of the ``charset`` encoding when ``charset`` is set. The
-    incoming parameter names are not decoded to unicode unless the
-    ``decode_param_names`` option is enabled.
-
-    When unicode is expected, ``charset`` will overridden by the the
-    value of the ``Content-Type`` header's charset parameter if one was
-    specified by the client.
-
-    The class variable ``defaults`` specifies default values for
-    ``charset``, ``errors``, and ``langauge``. These can be overridden for the
-    current request via the registry.
-        
-    The ``language`` default value is considered the fallback during i18n
-    translations to ensure in odd cases that mixed languages don't occur should
-    the ``language`` file contain the string but not another language in the
-    accepted languages list. The ``language`` value only applies when getting
-    a list of accepted languages from the HTTP Accept header.
-    
-    This behavior is duplicated from Aquarium, and may seem strange but is
-    very useful. Normally, everything in the code is in "en-us".  However, 
-    the "en-us" translation catalog is usually empty.  If the user requests
-    ``["en-us", "zh-cn"]`` and a translation isn't found for a string in
-    "en-us", you don't want gettext to fallback to "zh-cn".  You want it to 
-    just use the string itself.  Hence, if a string isn't found in the
-    ``language`` catalog, the string in the source code will be used.
-
-    *All* other state is kept in the environment dictionary; this is
-    essential for interoperability.
-
-    You are free to subclass this object.
-
-    """
-    defaults = StackedObjectProxy(default=dict(charset=None, errors='replace',
-                                               decode_param_names=False,
-                                               language='en-us'))
-    def __init__(self, environ):
-        self.environ = environ
-        # This isn't "state" really, since the object is derivative:
-        self.headers = EnvironHeaders(environ)
-        
-        defaults = self.defaults._current_obj()
-        self.charset = defaults.get('charset')
-        if self.charset:
-            # There's a charset: params will be coerced to unicode. In that
-            # case, attempt to use the charset specified by the browser
-            browser_charset = self.determine_browser_charset()
-            if browser_charset:
-                self.charset = browser_charset
-        self.errors = defaults.get('errors', 'strict')
-        self.decode_param_names = defaults.get('decode_param_names', False)
-        self._languages = None
-    
-    body = environ_getter('wsgi.input')
-    scheme = environ_getter('wsgi.url_scheme')
-    method = environ_getter('REQUEST_METHOD')
-    script_name = environ_getter('SCRIPT_NAME')
-    path_info = environ_getter('PATH_INFO')
-
-    def urlvars(self):
-        """
-        Return any variables matched in the URL (e.g.,
-        ``wsgiorg.routing_args``).
-        """
-        if 'paste.urlvars' in self.environ:
-            return self.environ['paste.urlvars']
-        elif 'wsgiorg.routing_args' in self.environ:
-            return self.environ['wsgiorg.routing_args'][1]
-        else:
-            return {}
-    urlvars = property(urlvars, doc=urlvars.__doc__)
-    
-    def is_xhr(self):
-        """Returns a boolean if X-Requested-With is present and a XMLHttpRequest"""
-        return self.environ.get('HTTP_X_REQUESTED_WITH', '') == 'XMLHttpRequest'
-    is_xhr = property(is_xhr, doc=is_xhr.__doc__)
-    
-    def host(self):
-        """Host name provided in HTTP_HOST, with fall-back to SERVER_NAME"""
-        return self.environ.get('HTTP_HOST', self.environ.get('SERVER_NAME'))
-    host = property(host, doc=host.__doc__)
-
-    def languages(self):
-        """Return a list of preferred languages, most preferred first.
-        
-        The list may be empty.
-        """
-        if self._languages is not None:
-            return self._languages
-        acceptLanguage = self.environ.get('HTTP_ACCEPT_LANGUAGE')
-        langs = ACCEPT_LANGUAGE.parse(self.environ)
-        fallback = self.defaults.get('language', 'en-us')
-        if not fallback:
-            return langs
-        if fallback not in langs:
-            langs.append(fallback)
-        index = langs.index(fallback)
-        langs[index+1:] = []
-        self._languages = langs
-        return self._languages
-    languages = property(languages, doc=languages.__doc__)
-    
-    def _GET(self):
-        return parse_dict_querystring(self.environ)
-
-    def GET(self):
-        """
-        Dictionary-like object representing the QUERY_STRING
-        parameters. Always present, if possibly empty.
-
-        If the same key is present in the query string multiple times, a
-        list of its values can be retrieved from the ``MultiDict`` via
-        the ``getall`` method.
-
-        Returns a ``MultiDict`` container or a ``UnicodeMultiDict`` when
-        ``charset`` is set.
-        """
-        params = self._GET()
-        if self.charset:
-            params = UnicodeMultiDict(params, encoding=self.charset,
-                                      errors=self.errors,
-                                      decode_keys=self.decode_param_names)
-        return params
-    GET = property(GET, doc=GET.__doc__)
-
-    def _POST(self):
-        return parse_formvars(self.environ, include_get_vars=False)
-
-    def POST(self):
-        """Dictionary-like object representing the POST body.
-
-        Most values are encoded strings, or unicode strings when
-        ``charset`` is set. There may also be FieldStorage objects
-        representing file uploads. If this is not a POST request, or the
-        body is not encoded fields (e.g., an XMLRPC request) then this
-        will be empty.
-
-        This will consume wsgi.input when first accessed if applicable,
-        but the raw version will be put in
-        environ['paste.parsed_formvars'].
-
-        Returns a ``MultiDict`` container or a ``UnicodeMultiDict`` when
-        ``charset`` is set.
-        """
-        params = self._POST()
-        if self.charset:
-            params = UnicodeMultiDict(params, encoding=self.charset,
-                                      errors=self.errors,
-                                      decode_keys=self.decode_param_names)
-        return params
-    POST = property(POST, doc=POST.__doc__)
-
-    def params(self):
-        """Dictionary-like object of keys from POST, GET, URL dicts
-
-        Return a key value from the parameters, they are checked in the
-        following order: POST, GET, URL
-
-        Additional methods supported:
-
-        ``getlist(key)``
-            Returns a list of all the values by that key, collected from
-            POST, GET, URL dicts
-
-        Returns a ``MultiDict`` container or a ``UnicodeMultiDict`` when
-        ``charset`` is set.
-        """
-        params = MultiDict()
-        params.update(self._POST())
-        params.update(self._GET())
-        if self.charset:
-            params = UnicodeMultiDict(params, encoding=self.charset,
-                                      errors=self.errors,
-                                      decode_keys=self.decode_param_names)
-        return params
-    params = property(params, doc=params.__doc__)
-
-    def cookies(self):
-        """Dictionary of cookies keyed by cookie name.
-
-        Just a plain dictionary, may be empty but not None.
-        
-        """
-        return get_cookie_dict(self.environ)
-    cookies = property(cookies, doc=cookies.__doc__)
-
-    def determine_browser_charset(self):
-        """
-        Determine the encoding as specified by the browser via the
-        Content-Type's charset parameter, if one is set
-        """
-        charset_match = _CHARSET_RE.search(self.headers.get('Content-Type', ''))
-        if charset_match:
-            return charset_match.group(1)
-
-    def match_accept(self, mimetypes):
-        """Return a list of specified mime-types that the browser's HTTP Accept
-        header allows in the order provided."""
-        return desired_matches(mimetypes, 
-                               self.environ.get('HTTP_ACCEPT', '*/*'))
-
-    def __repr__(self):
-        """Show important attributes of the WSGIRequest"""
-        pf = pformat
-        msg = '<%s.%s object at 0x%x method=%s,' % \
-            (self.__class__.__module__, self.__class__.__name__,
-             id(self), pf(self.method))
-        msg += '\nscheme=%s, host=%s, script_name=%s, path_info=%s,' % \
-            (pf(self.scheme), pf(self.host), pf(self.script_name),
-             pf(self.path_info))
-        msg += '\nlanguages=%s,' % pf(self.languages)
-        if self.charset:
-            msg += ' charset=%s, errors=%s,' % (pf(self.charset),
-                                                pf(self.errors))
-        msg += '\nGET=%s,' % pf(self.GET)
-        msg += '\nPOST=%s,' % pf(self.POST)
-        msg += '\ncookies=%s>' % pf(self.cookies)
-        return msg
-
-class WSGIResponse(object):
-    """A basic HTTP response with content, headers, and out-bound cookies
-
-    The class variable ``defaults`` specifies default values for
-    ``content_type``, ``charset`` and ``errors``. These can be overridden
-    for the current request via the registry.
-
-    """
-    defaults = StackedObjectProxy(
-        default=dict(content_type='text/html', charset='utf-8', 
-                     errors='strict', headers={'Cache-Control':'no-cache'})
-        )
-    def __init__(self, content='', mimetype=None, code=200):
-        self._iter = None
-        self._is_str_iter = True
-
-        self.content = content
-        self.headers = HeaderDict()
-        self.cookies = SimpleCookie()
-        self.status_code = code
-
-        defaults = self.defaults._current_obj()
-        if not mimetype:
-            mimetype = defaults.get('content_type', 'text/html')
-            charset = defaults.get('charset')
-            if charset:
-                mimetype = '%s; charset=%s' % (mimetype, charset)
-        self.headers.update(defaults.get('headers', {}))
-        self.headers['Content-Type'] = mimetype
-        self.errors = defaults.get('errors', 'strict')
-
-    def __str__(self):
-        """Returns a rendition of the full HTTP message, including headers.
-
-        When the content is an iterator, the actual content is replaced with the
-        output of str(iterator) (to avoid exhausting the iterator).
-        """
-        if self._is_str_iter:
-            content = ''.join(self.get_content())
-        else:
-            content = str(self.content)
-        return '\n'.join(['%s: %s' % (key, value)
-            for key, value in self.headers.headeritems()]) \
-            + '\n\n' + content
-    
-    def __call__(self, environ, start_response):
-        """Convenience call to return output and set status information
-        
-        Conforms to the WSGI interface for calling purposes only.
-        
-        Example usage:
-        
-        .. code-block:: python
-
-            def wsgi_app(environ, start_response):
-                response = WSGIResponse()
-                response.write("Hello world")
-                response.headers['Content-Type'] = 'latin1'
-                return response(environ, start_response)
-        
-        """
-        status_text = STATUS_CODE_TEXT[self.status_code]
-        status = '%s %s' % (self.status_code, status_text)
-        response_headers = self.headers.headeritems()
-        for c in self.cookies.values():
-            response_headers.append(('Set-Cookie', c.output(header='')))
-        start_response(status, response_headers)
-        is_file = isinstance(self.content, file)
-        if 'wsgi.file_wrapper' in environ and is_file:
-            return environ['wsgi.file_wrapper'](self.content)
-        elif is_file:
-            return iter(lambda: self.content.read(), '')
-        return self.get_content()
-    
-    def determine_charset(self):
-        """
-        Determine the encoding as specified by the Content-Type's charset
-        parameter, if one is set
-        """
-        charset_match = _CHARSET_RE.search(self.headers.get('Content-Type', ''))
-        if charset_match:
-            return charset_match.group(1)
-    
-    def has_header(self, header):
-        """
-        Case-insensitive check for a header
-        """
-        warnings.warn('WSGIResponse.has_header is deprecated, use '
-                      'WSGIResponse.headers.has_key instead', DeprecationWarning,
-                      2)
-        return self.headers.has_key(header)
-
-    def set_cookie(self, key, value='', max_age=None, expires=None, path='/',
-                   domain=None, secure=None, httponly=None):
-        """
-        Define a cookie to be sent via the outgoing HTTP headers
-        """
-        self.cookies[key] = value
-        for var_name, var_value in [
-            ('max_age', max_age), ('path', path), ('domain', domain),
-            ('secure', secure), ('expires', expires), ('httponly', httponly)]:
-            if var_value is not None and var_value is not False:
-                self.cookies[key][var_name.replace('_', '-')] = var_value
-
-    def delete_cookie(self, key, path='/', domain=None):
-        """
-        Notify the browser the specified cookie has expired and should be
-        deleted (via the outgoing HTTP headers)
-        """
-        self.cookies[key] = ''
-        if path is not None:
-            self.cookies[key]['path'] = path
-        if domain is not None:
-            self.cookies[key]['domain'] = domain
-        self.cookies[key]['expires'] = 0
-        self.cookies[key]['max-age'] = 0
-
-    def _set_content(self, content):
-        if hasattr(content, '__iter__'):
-            self._iter = content
-            if isinstance(content, list):
-                self._is_str_iter = True
-            else:
-                self._is_str_iter = False
-        else:
-            self._iter = [content]
-            self._is_str_iter = True
-    content = property(lambda self: self._iter, _set_content,
-                       doc='Get/set the specified content, where content can '
-                       'be: a string, a list of strings, a generator function '
-                       'that yields strings, or an iterable object that '
-                       'produces strings.')
-
-    def get_content(self):
-        """
-        Returns the content as an iterable of strings, encoding each element of
-        the iterator from a Unicode object if necessary.
-        """
-        charset = self.determine_charset()
-        if charset:
-            return encode_unicode_app_iter(self.content, charset, self.errors)
-        else:
-            return self.content
-    
-    def wsgi_response(self):
-        """
-        Return this WSGIResponse as a tuple of WSGI formatted data, including:
-        (status, headers, iterable)
-        """
-        status_text = STATUS_CODE_TEXT[self.status_code]
-        status = '%s %s' % (self.status_code, status_text)
-        response_headers = self.headers.headeritems()
-        for c in self.cookies.values():
-            response_headers.append(('Set-Cookie', c.output(header='')))
-        return status, response_headers, self.get_content()
-    
-    # The remaining methods partially implement the file-like object interface.
-    # See http://docs.python.org/lib/bltin-file-objects.html
-    def write(self, content):
-        if not self._is_str_iter:
-            raise IOError, "This %s instance's content is not writable: (content " \
-                'is an iterator)' % self.__class__.__name__
-        self.content.append(content)
-
-    def flush(self):
-        pass
-
-    def tell(self):
-        if not self._is_str_iter:
-            raise IOError, 'This %s instance cannot tell its position: (content ' \
-                'is an iterator)' % self.__class__.__name__
-        return sum([len(chunk) for chunk in self._iter])
-
-    ########################################
-    ## Content-type and charset
-
-    def charset__get(self):
-        """
-        Get/set the charset (in the Content-Type)
-        """
-        header = self.headers.get('content-type')
-        if not header:
-            return None
-        match = _CHARSET_RE.search(header)
-        if match:
-            return match.group(1)
-        return None
-
-    def charset__set(self, charset):
-        if charset is None:
-            del self.charset
-            return
-        try:
-            header = self.headers.pop('content-type')
-        except KeyError:
-            raise AttributeError(
-                "You cannot set the charset when no content-type is defined")
-        match = _CHARSET_RE.search(header)
-        if match:
-            header = header[:match.start()] + header[match.end():]
-        header += '; charset=%s' % charset
-        self.headers['content-type'] = header
-
-    def charset__del(self):
-        try:
-            header = self.headers.pop('content-type')
-        except KeyError:
-            # Don't need to remove anything
-            return
-        match = _CHARSET_RE.search(header)
-        if match:
-            header = header[:match.start()] + header[match.end():]
-        self.headers['content-type'] = header
-
-    charset = property(charset__get, charset__set, charset__del, doc=charset__get.__doc__)
-
-    def content_type__get(self):
-        """
-        Get/set the Content-Type header (or None), *without* the
-        charset or any parameters.
-
-        If you include parameters (or ``;`` at all) when setting the
-        content_type, any existing parameters will be deleted;
-        otherwise they will be preserved.
-        """
-        header = self.headers.get('content-type')
-        if not header:
-            return None
-        return header.split(';', 1)[0]
-
-    def content_type__set(self, value):
-        if ';' not in value:
-            header = self.headers.get('content-type', '')
-            if ';' in header:
-                params = header.split(';', 1)[1]
-                value += ';' + params
-        self.headers['content-type'] = value
-
-    def content_type__del(self):
-        try:
-            del self.headers['content-type']
-        except KeyError:
-            pass
-
-    content_type = property(content_type__get, content_type__set,
-                            content_type__del, doc=content_type__get.__doc__)
-
-## @@ I'd love to remove this, but paste.httpexceptions.get_exception
-##    doesn't seem to work...
-# See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
-STATUS_CODE_TEXT = {
-    100: 'CONTINUE',
-    101: 'SWITCHING PROTOCOLS',
-    200: 'OK',
-    201: 'CREATED',
-    202: 'ACCEPTED',
-    203: 'NON-AUTHORITATIVE INFORMATION',
-    204: 'NO CONTENT',
-    205: 'RESET CONTENT',
-    206: 'PARTIAL CONTENT',
-    226: 'IM USED',
-    300: 'MULTIPLE CHOICES',
-    301: 'MOVED PERMANENTLY',
-    302: 'FOUND',
-    303: 'SEE OTHER',
-    304: 'NOT MODIFIED',
-    305: 'USE PROXY',
-    306: 'RESERVED',
-    307: 'TEMPORARY REDIRECT',
-    400: 'BAD REQUEST',
-    401: 'UNAUTHORIZED',
-    402: 'PAYMENT REQUIRED',
-    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',
-    500: 'INTERNAL SERVER ERROR',
-    501: 'NOT IMPLEMENTED',
-    502: 'BAD GATEWAY',
-    503: 'SERVICE UNAVAILABLE',
-    504: 'GATEWAY TIMEOUT',
-    505: 'HTTP VERSION NOT SUPPORTED',
-}
diff --git a/lib/recaptcha/__init__.py b/lib/recaptcha/__init__.py
@@ -1 +0,0 @@
-__import__('pkg_resources').declare_namespace(__name__)
diff --git a/lib/recaptcha/client/__init__.py b/lib/recaptcha/client/__init__.py
diff --git a/lib/recaptcha/client/captcha.py b/lib/recaptcha/client/captcha.py
@@ -1,92 +0,0 @@
-import urllib2, urllib
-
-API_SSL_SERVER="https://api-secure.recaptcha.net"
-API_SERVER="http://api.recaptcha.net"
-VERIFY_SERVER="api-verify.recaptcha.net"
-
-class RecaptchaResponse(object):
-    def __init__(self, is_valid, error_code=None):
-        self.is_valid = is_valid
-        self.error_code = error_code
-
-def displayhtml (public_key,
-                 use_ssl = False,
-                 error = None):
-    """Gets the HTML to display for reCAPTCHA
-
-    public_key -- The public api key
-    use_ssl -- Should the request be sent over ssl?
-    error -- An error message to display (from RecaptchaResponse.error_code)"""
-
-    error_param = ''
-    if error:
-	error_param = '&error=%s' % error
-
-    if use_ssl:
-        server = API_SSL_SERVER
-    else:
-        server = API_SERVER
-
-    return """<script type="text/javascript" src="%(ApiServer)s/challenge?k=%(PublicKey)s%(ErrorParam)s"></script>
-
-<noscript>
-  <iframe src="%(ApiServer)s/noscript?k=%(PublicKey)s%(ErrorParam)s" height="300" width="500" frameborder="0"></iframe><br />
-  <textarea name="recaptcha_challenge_field" rows="3" cols="40"></textarea>
-  <input type='hidden' name='recaptcha_response_field' value='manual_challenge' />
-</noscript>
-""" % {
-        'ApiServer' : server,
-        'PublicKey' : public_key,
-        'ErrorParam' : error_param,
-        }
-
-
-def submit (recaptcha_challenge_field,
-            recaptcha_response_field,
-            private_key,
-            remoteip):
-    """
-    Submits a reCAPTCHA request for verification. Returns RecaptchaResponse
-    for the request
-
-    recaptcha_challenge_field -- The value of recaptcha_challenge_field from the form
-    recaptcha_response_field -- The value of recaptcha_response_field from the form
-    private_key -- your reCAPTCHA private key
-    remoteip -- the user's ip address
-    """
-
-    if not (recaptcha_response_field and recaptcha_challenge_field and
-            len (recaptcha_response_field) and len (recaptcha_challenge_field)):
-        return RecaptchaResponse (is_valid = False, error_code = 'incorrect-captcha-sol')
-    
-    
-    
-    params = urllib.urlencode ({
-	    'privatekey': private_key,
-            'remoteip' : remoteip,
-	    'challenge': recaptcha_challenge_field,
-	    'response' : recaptcha_response_field,
-	    })
-
-    request = urllib2.Request (
-        url = "http://%s/verify" % VERIFY_SERVER,
-        data = params,
-        headers = {
-            "Content-type": "application/x-www-form-urlencoded",
-            "User-agent": "reCAPTCHA Python"
-            }
-        )
-    
-    httpresp = urllib2.urlopen (request)
-
-    return_values = httpresp.read ().splitlines ();
-    httpresp.close();
-
-    return_code = return_values [0]
-
-    if (return_code == "true"):
-        return RecaptchaResponse (is_valid=True)
-    else:
-        return RecaptchaResponse (is_valid=False, error_code = return_values [1])
-
-
diff --git a/lib/recaptcha/client/mailhide.py b/lib/recaptcha/client/mailhide.py
@@ -1,68 +0,0 @@
-import base64
-import cgi
-
-try:
-    from Crypto.Cipher import AES
-except:
-    raise Exception ("You need the pycrpyto library: http://cheeseshop.python.org/pypi/pycrypto/")
-
-MAIL_HIDE_BASE="http://mailhide.recaptcha.net"
-
-def asurl (email,
-                 public_key,
-                 private_key):
-    """Wraps an email address with reCAPTCHA mailhide and
-    returns the url. public_key is the public key from reCAPTCHA
-    (in the base 64 encoded format). Private key is the AES key, and should
-    be 32 hex chars."""
-    
-    cryptmail = _encrypt_string (email, base64.b16decode (private_key, casefold=True), '\0' * 16)
-    base64crypt = base64.urlsafe_b64encode (cryptmail)
-
-    return "%s/d?k=%s&c=%s" % (MAIL_HIDE_BASE, public_key, base64crypt)
-
-def ashtml (email,
-                  public_key,
-                  private_key):
-    """Wraps an email address with reCAPTCHA Mailhide and
-    returns html that displays the email"""
-
-    url = asurl (email, public_key, private_key)
-    (userpart, domainpart) = _doterizeemail (email)
-
-    return """%(user)s<a href='%(url)s' onclick="window.open('%(url)s', '', 'toolbar=0,scrollbars=0,location=0,statusbar=0,menubar=0,resizable=0,width=500,height=300'); return false;" title="Reveal this e-mail address">...</a>@%(domain)s""" % {
-        'user' : cgi.escape (userpart),
-        'domain' : cgi.escape (domainpart),
-        'url'  : cgi.escape (url),
-        }
-    
-
-def _pad_string (str, block_size):
-    numpad = block_size - (len (str) % block_size)
-    return str + numpad * chr (numpad)
-
-def _encrypt_string (str, aes_key, aes_iv):
-    if len (aes_key) != 16:
-	raise Exception ("expecting key of length 16")
-    if len (aes_iv) != 16:
-	raise Exception ("expecting iv of length 16")
-    return AES.new (aes_key, AES.MODE_CBC, aes_iv).encrypt (_pad_string (str, 16))
-
-def _doterizeemail (email):
-    """replaces part of the username with dots"""
-    
-    try:
-        [user, domain] = email.split ('@')
-    except:
-        # handle invalid emails... sorta
-        user = email
-        domain = ""
-
-    if len(user) <= 4:
-        user_prefix = user[:1]
-    elif len(user) <= 6:
-        user_prefix = user[:3]
-    else:
-        user_prefix = user[:4]
-
-    return (user_prefix, domain)
diff --git a/lib/smartypants.py b/lib/smartypants.py
@@ -1,903 +0,0 @@
-#!/usr/bin/python
-
-r"""
-==============
-smartypants.py
-==============
-
-----------------------------
-SmartyPants ported to Python
-----------------------------
-
-Ported by `Chad Miller`_
-Copyright (c) 2004, 2007 Chad Miller
-
-original `SmartyPants`_ by `John Gruber`_
-Copyright (c) 2003 John Gruber
-
-
-Synopsis
-========
-
-A smart-quotes plugin for Pyblosxom_.
-
-The priginal "SmartyPants" is a free web publishing plug-in for Movable Type,
-Blosxom, and BBEdit that easily translates plain ASCII punctuation characters
-into "smart" typographic punctuation HTML entities.
-
-This software, *smartypants.py*, endeavours to be a functional port of
-SmartyPants to Python, for use with Pyblosxom_.
-
-
-Description
-===========
-
-SmartyPants can perform the following transformations:
-
-- Straight quotes ( " and ' ) into "curly" quote HTML entities
-- Backticks-style quotes (\`\`like this'') into "curly" quote HTML entities
-- Dashes (``--`` and ``---``) into en- and em-dash entities
-- Three consecutive dots (``...`` or ``. . .``) into an ellipsis entity
-
-This means you can write, edit, and save your posts using plain old
-ASCII straight quotes, plain dashes, and plain dots, but your published
-posts (and final HTML output) will appear with smart quotes, em-dashes,
-and proper ellipses.
-
-SmartyPants does not modify characters within ``<pre>``, ``<code>``, ``<kbd>``,
-``<math>`` or ``<script>`` tag blocks. Typically, these tags are used to
-display text where smart quotes and other "smart punctuation" would not be
-appropriate, such as source code or example markup.
-
-
-Backslash Escapes
-=================
-
-If you need to use literal straight quotes (or plain hyphens and
-periods), SmartyPants accepts the following backslash escape sequences
-to force non-smart punctuation. It does so by transforming the escape
-sequence into a decimal-encoded HTML entity:
-
-(FIXME:  table here.)
-
-.. comment    It sucks that there's a disconnect between the visual layout and table markup when special characters are involved.
-.. comment ======  =====  =========
-.. comment Escape  Value  Character
-.. comment ======  =====  =========
-.. comment \\\\\\\\    &#92;  \\\\
-.. comment \\\\"     &#34;  "
-.. comment \\\\'     &#39;  '
-.. comment \\\\.     &#46;  .
-.. comment \\\\-     &#45;  \-
-.. comment \\\\`     &#96;  \`
-.. comment ======  =====  =========
-
-This is useful, for example, when you want to use straight quotes as
-foot and inch marks: 6'2" tall; a 17" iMac.
-
-Options
-=======
-
-For Pyblosxom users, the ``smartypants_attributes`` attribute is where you
-specify configuration options. 
-
-Numeric values are the easiest way to configure SmartyPants' behavior:
-
-"0"
-	Suppress all transformations. (Do nothing.)
-"1" 
-	Performs default SmartyPants transformations: quotes (including
-	\`\`backticks'' -style), em-dashes, and ellipses. "``--``" (dash dash)
-	is used to signify an em-dash; there is no support for en-dashes.
-
-"2"
-	Same as smarty_pants="1", except that it uses the old-school typewriter
-	shorthand for dashes:  "``--``" (dash dash) for en-dashes, "``---``"
-	(dash dash dash)
-	for em-dashes.
-
-"3"
-	Same as smarty_pants="2", but inverts the shorthand for dashes:
-	"``--``" (dash dash) for em-dashes, and "``---``" (dash dash dash) for
-	en-dashes.
-
-"-1"
-	Stupefy mode. Reverses the SmartyPants transformation process, turning
-	the HTML entities produced by SmartyPants into their ASCII equivalents.
-	E.g.  "&#8220;" is turned into a simple double-quote ("), "&#8212;" is
-	turned into two dashes, etc.
-
-
-The following single-character attribute values can be combined to toggle
-individual transformations from within the smarty_pants attribute. For
-example, to educate normal quotes and em-dashes, but not ellipses or
-\`\`backticks'' -style quotes:
-
-``py['smartypants_attributes'] = "1"``
-
-"q"
-	Educates normal quote characters: (") and (').
-
-"b"
-	Educates \`\`backticks'' -style double quotes.
-
-"B"
-	Educates \`\`backticks'' -style double quotes and \`single' quotes.
-
-"d"
-	Educates em-dashes.
-
-"D"
-	Educates em-dashes and en-dashes, using old-school typewriter shorthand:
-	(dash dash) for en-dashes, (dash dash dash) for em-dashes.
-
-"i"
-	Educates em-dashes and en-dashes, using inverted old-school typewriter
-	shorthand: (dash dash) for em-dashes, (dash dash dash) for en-dashes.
-
-"e"
-	Educates ellipses.
-
-"w"
-	Translates any instance of ``&quot;`` into a normal double-quote character.
-	This should be of no interest to most people, but of particular interest
-	to anyone who writes their posts using Dreamweaver, as Dreamweaver
-	inexplicably uses this entity to represent a literal double-quote
-	character. SmartyPants only educates normal quotes, not entities (because
-	ordinarily, entities are used for the explicit purpose of representing the
-	specific character they represent). The "w" option must be used in
-	conjunction with one (or both) of the other quote options ("q" or "b").
-	Thus, if you wish to apply all SmartyPants transformations (quotes, en-
-	and em-dashes, and ellipses) and also translate ``&quot;`` entities into
-	regular quotes so SmartyPants can educate them, you should pass the
-	following to the smarty_pants attribute:
-
-The ``smartypants_forbidden_flavours`` list contains pyblosxom flavours for 
-which no Smarty Pants rendering will occur.
-
-
-Caveats
-=======
-
-Why You Might Not Want to Use Smart Quotes in Your Weblog
----------------------------------------------------------
-
-For one thing, you might not care.
-
-Most normal, mentally stable individuals do not take notice of proper
-typographic punctuation. Many design and typography nerds, however, break
-out in a nasty rash when they encounter, say, a restaurant sign that uses
-a straight apostrophe to spell "Joe's".
-
-If you're the sort of person who just doesn't care, you might well want to
-continue not caring. Using straight quotes -- and sticking to the 7-bit
-ASCII character set in general -- is certainly a simpler way to live.
-
-Even if you I *do* care about accurate typography, you still might want to
-think twice before educating the quote characters in your weblog. One side
-effect of publishing curly quote HTML entities is that it makes your
-weblog a bit harder for others to quote from using copy-and-paste. What
-happens is that when someone copies text from your blog, the copied text
-contains the 8-bit curly quote characters (as well as the 8-bit characters
-for em-dashes and ellipses, if you use these options). These characters
-are not standard across different text encoding methods, which is why they
-need to be encoded as HTML entities.
-
-People copying text from your weblog, however, may not notice that you're
-using curly quotes, and they'll go ahead and paste the unencoded 8-bit
-characters copied from their browser into an email message or their own
-weblog. When pasted as raw "smart quotes", these characters are likely to
-get mangled beyond recognition.
-
-That said, my own opinion is that any decent text editor or email client
-makes it easy to stupefy smart quote characters into their 7-bit
-equivalents, and I don't consider it my problem if you're using an
-indecent text editor or email client.
-
-
-Algorithmic Shortcomings
-------------------------
-
-One situation in which quotes will get curled the wrong way is when
-apostrophes are used at the start of leading contractions. For example:
-
-``'Twas the night before Christmas.``
-
-In the case above, SmartyPants will turn the apostrophe into an opening
-single-quote, when in fact it should be a closing one. I don't think
-this problem can be solved in the general case -- every word processor
-I've tried gets this wrong as well. In such cases, it's best to use the
-proper HTML entity for closing single-quotes (``&#8217;``) by hand.
-
-
-Bugs
-====
-
-To file bug reports or feature requests (other than topics listed in the
-Caveats section above) please send email to: mailto:smartypantspy@chad.org
-
-If the bug involves quotes being curled the wrong way, please send example
-text to illustrate.
-
-To Do list
-----------
-
-- Provide a function for use within templates to quote anything at all.
-
-
-Version History
-===============
-
-1.5_1.6: Fri, 27 Jul 2007 07:06:40 -0400
-	- Fixed bug where blocks of precious unalterable text was instead
-	  interpreted.  Thanks to Le Roux and Dirk van Oosterbosch.
-	
-1.5_1.5: Sat, 13 Aug 2005 15:50:24 -0400
-	- Fix bogus magical quotation when there is no hint that the 
-	  user wants it, e.g., in "21st century".  Thanks to Nathan Hamblen.
-	- Be smarter about quotes before terminating numbers in an en-dash'ed
-	  range.
-
-1.5_1.4: Thu, 10 Feb 2005 20:24:36 -0500
-	- Fix a date-processing bug, as reported by jacob childress.
-	- Begin a test-suite for ensuring correct output.
-	- Removed import of "string", since I didn't really need it.
-	  (This was my first every Python program.  Sue me!)
-
-1.5_1.3: Wed, 15 Sep 2004 18:25:58 -0400
-	- Abort processing if the flavour is in forbidden-list.  Default of 
-	  [ "rss" ]   (Idea of Wolfgang SCHNERRING.)
-	- Remove stray virgules from en-dashes.  Patch by Wolfgang SCHNERRING.
-
-1.5_1.2: Mon, 24 May 2004 08:14:54 -0400
-	- Some single quotes weren't replaced properly.  Diff-tesuji played
-	  by Benjamin GEIGER.
-
-1.5_1.1: Sun, 14 Mar 2004 14:38:28 -0500
-	- Support upcoming pyblosxom 0.9 plugin verification feature.
-
-1.5_1.0: Tue, 09 Mar 2004 08:08:35 -0500
-	- Initial release
-
-Version Information
--------------------
-
-Version numbers will track the SmartyPants_ version numbers, with the addition
-of an underscore and the smartypants.py version on the end.
-
-New versions will be available at `http://wiki.chad.org/SmartyPantsPy`_
-
-.. _http://wiki.chad.org/SmartyPantsPy: http://wiki.chad.org/SmartyPantsPy
-
-Authors
-=======
-
-`John Gruber`_ did all of the hard work of writing this software in Perl for
-`Movable Type`_ and almost all of this useful documentation.  `Chad Miller`_
-ported it to Python to use with Pyblosxom_.
-
-
-Additional Credits
-==================
-
-Portions of the SmartyPants original work are based on Brad Choate's nifty
-MTRegex plug-in.  `Brad Choate`_ also contributed a few bits of source code to
-this plug-in.  Brad Choate is a fine hacker indeed.
-
-`Jeremy Hedley`_ and `Charles Wiltgen`_ deserve mention for exemplary beta
-testing of the original SmartyPants.
-
-`Rael Dornfest`_ ported SmartyPants to Blosxom.
-
-.. _Brad Choate: http://bradchoate.com/
-.. _Jeremy Hedley: http://antipixel.com/
-.. _Charles Wiltgen: http://playbacktime.com/
-.. _Rael Dornfest: http://raelity.org/
-
-
-Copyright and License
-=====================
-
-SmartyPants_ license::
-
-	Copyright (c) 2003 John Gruber
-	(http://daringfireball.net/)
-	All rights reserved.
-
-	Redistribution and use in source and binary forms, with or without
-	modification, are permitted provided that the following conditions are
-	met:
-
-	*   Redistributions of source code must retain the above copyright
-		notice, this list of conditions and the following disclaimer.
-
-	*   Redistributions in binary form must reproduce the above copyright
-		notice, this list of conditions and the following disclaimer in
-		the documentation and/or other materials provided with the
-		distribution.
-
-	*   Neither the name "SmartyPants" nor the names of its contributors 
-		may be used to endorse or promote products derived from this
-		software without specific prior written permission.
-
-	This software is provided by the copyright holders and contributors "as
-	is" and any express or implied warranties, including, but not limited
-	to, the implied warranties of merchantability and fitness for a
-	particular purpose are disclaimed. In no event shall the copyright
-	owner or contributors be liable for any direct, indirect, incidental,
-	special, exemplary, or consequential damages (including, but not
-	limited to, procurement of substitute goods or services; loss of use,
-	data, or profits; or business interruption) however caused and on any
-	theory of liability, whether in contract, strict liability, or tort
-	(including negligence or otherwise) arising in any way out of the use
-	of this software, even if advised of the possibility of such damage.
-
-
-smartypants.py license::
-
-	smartypants.py is a derivative work of SmartyPants.
-	
-	Redistribution and use in source and binary forms, with or without
-	modification, are permitted provided that the following conditions are
-	met:
-
-	*   Redistributions of source code must retain the above copyright
-		notice, this list of conditions and the following disclaimer.
-
-	*   Redistributions in binary form must reproduce the above copyright
-		notice, this list of conditions and the following disclaimer in
-		the documentation and/or other materials provided with the
-		distribution.
-
-	This software is provided by the copyright holders and contributors "as
-	is" and any express or implied warranties, including, but not limited
-	to, the implied warranties of merchantability and fitness for a
-	particular purpose are disclaimed. In no event shall the copyright
-	owner or contributors be liable for any direct, indirect, incidental,
-	special, exemplary, or consequential damages (including, but not
-	limited to, procurement of substitute goods or services; loss of use,
-	data, or profits; or business interruption) however caused and on any
-	theory of liability, whether in contract, strict liability, or tort
-	(including negligence or otherwise) arising in any way out of the use
-	of this software, even if advised of the possibility of such damage.
-
-
-
-.. _John Gruber: http://daringfireball.net/
-.. _Chad Miller: http://web.chad.org/
-
-.. _Pyblosxom: http://roughingit.subtlehints.net/pyblosxom
-.. _SmartyPants: http://daringfireball.net/projects/smartypants/
-.. _Movable Type: http://www.movabletype.org/
-
-"""
-
-default_smartypants_attr = "1"
-
-import re
-
-tags_to_skip_regex = re.compile(r"<(/)?(pre|code|kbd|script|math)[^>]*>", re.I)
-
-
-def verify_installation(request):
-	return 1
-	# assert the plugin is functional
-
-
-def cb_story(args):
-	global default_smartypants_attr
-
-	try:
-		forbidden_flavours = args["entry"]["smartypants_forbidden_flavours"]
-	except KeyError:
-		forbidden_flavours = [ "rss" ]
-
-	try:
-		attributes = args["entry"]["smartypants_attributes"]
-	except KeyError:
-		attributes = default_smartypants_attr
-
-	if attributes is None:
-		attributes = default_smartypants_attr
-
-	entryData = args["entry"].getData()
-
-	try:
-		if args["request"]["flavour"] in forbidden_flavours:
-			return
-	except KeyError:
-		if "&lt;" in args["entry"]["body"][0:15]:  # sniff the stream
-			return  # abort if it looks like escaped HTML.  FIXME
-
-	# FIXME: make these configurable, perhaps?
-	args["entry"]["body"] = smartyPants(entryData, attributes)
-	args["entry"]["title"] = smartyPants(args["entry"]["title"], attributes)
-
-
-### interal functions below here
-
-def smartyPants(text, attr=default_smartypants_attr):
-	convert_quot = False  # should we translate &quot; entities into normal quotes?
-
-	# Parse attributes:
-	# 0 : do nothing
-	# 1 : set all
-	# 2 : set all, using old school en- and em- dash shortcuts
-	# 3 : set all, using inverted old school en and em- dash shortcuts
-	# 
-	# q : quotes
-	# b : backtick quotes (``double'' only)
-	# B : backtick quotes (``double'' and `single')
-	# d : dashes
-	# D : old school dashes
-	# i : inverted old school dashes
-	# e : ellipses
-	# w : convert &quot; entities to " for Dreamweaver users
-
-	skipped_tag_stack = []
-	do_dashes = "0"
-	do_backticks = "0"
-	do_quotes = "0"
-	do_ellipses = "0"
-	do_stupefy = "0"
-
-	if attr == "0":
-		# Do nothing.
-		return text
-	elif attr == "1":
-		do_quotes    = "1"
-		do_backticks = "1"
-		do_dashes    = "1"
-		do_ellipses  = "1"
-	elif attr == "2":
-		# Do everything, turn all options on, use old school dash shorthand.
-		do_quotes    = "1"
-		do_backticks = "1"
-		do_dashes    = "2"
-		do_ellipses  = "1"
-	elif attr == "3":
-		# Do everything, turn all options on, use inverted old school dash shorthand.
-		do_quotes    = "1"
-		do_backticks = "1"
-		do_dashes    = "3"
-		do_ellipses  = "1"
-	elif attr == "-1":
-		# Special "stupefy" mode.
-		do_stupefy   = "1"
-	else:
-		for c in attr:
-			if c == "q": do_quotes = "1"
-			elif c == "b": do_backticks = "1"
-			elif c == "B": do_backticks = "2"
-			elif c == "d": do_dashes = "1"
-			elif c == "D": do_dashes = "2"
-			elif c == "i": do_dashes = "3"
-			elif c == "e": do_ellipses = "1"
-			elif c == "w": convert_quot = "1"
-			else:
-				pass
-				# ignore unknown option
-
-	tokens = _tokenize(text)
-	result = []
-	in_pre = False
-
-	prev_token_last_char = ""
-	# This is a cheat, used to get some context
-	# for one-character tokens that consist of 
-	# just a quote char. What we do is remember
-	# the last character of the previous text
-	# token, to use as context to curl single-
-	# character quote tokens correctly.
-
-	for cur_token in tokens:
-		if cur_token[0] == "tag":
-			# Don't mess with quotes inside some tags.  This does not handle self <closing/> tags!
-			result.append(cur_token[1])
-			skip_match = tags_to_skip_regex.match(cur_token[1])
-			if skip_match is not None:
-				if not skip_match.group(1):
-					skipped_tag_stack.append(skip_match.group(2).lower())
-					in_pre = True
-				else:
-					if len(skipped_tag_stack) > 0:
-						if skip_match.group(2).lower() == skipped_tag_stack[-1]:
-							skipped_tag_stack.pop()
-						else:
-							pass
-							# This close doesn't match the open.  This isn't XHTML.  We should barf here.
-					if len(skipped_tag_stack) == 0:
-						in_pre = False
-		else:
-			t = cur_token[1]
-			last_char = t[-1:] # Remember last char of this token before processing.
-			if not in_pre:
-				oldstr = t
-				t = processEscapes(t)
-
-				if convert_quot != "0":
-					t = re.sub('&quot;', '"', t)
-
-				if do_dashes != "0":
-					if do_dashes == "1":
-						t = educateDashes(t)
-					if do_dashes == "2":
-						t = educateDashesOldSchool(t)
-					if do_dashes == "3":
-						t = educateDashesOldSchoolInverted(t)
-
-				if do_ellipses != "0":
-					t = educateEllipses(t)
-
-				# Note: backticks need to be processed before quotes.
-				if do_backticks != "0":
-					t = educateBackticks(t)
-
-				if do_backticks == "2":
-					t = educateSingleBackticks(t)
-
-				if do_quotes != "0":
-					if t == "'":
-						# Special case: single-character ' token
-						if re.match("\S", prev_token_last_char):
-							t = "&#8217;"
-						else:
-							t = "&#8216;"
-					elif t == '"':
-						# Special case: single-character " token
-						if re.match("\S", prev_token_last_char):
-							t = "&#8221;"
-						else:
-							t = "&#8220;"
-
-					else:
-						# Normal case:
-						t = educateQuotes(t)
-
-				if do_stupefy == "1":
-					t = stupefyEntities(t)
-
-			prev_token_last_char = last_char
-			result.append(t)
-
-	return "".join(result)
-
-
-def educateQuotes(str):
-	"""
-	Parameter:  String.
-	
-	Returns:	The string, with "educated" curly quote HTML entities.
-	
-	Example input:  "Isn't this fun?"
-	Example output: &#8220;Isn&#8217;t this fun?&#8221;
-	"""
-
-	oldstr = str
-	punct_class = r"""[!"#\$\%'()*+,-.\/:;<=>?\@\[\\\]\^_`{|}~]"""
-
-	# Special case if the very first character is a quote
-	# followed by punctuation at a non-word-break. Close the quotes by brute force:
-	str = re.sub(r"""^'(?=%s\\B)""" % (punct_class,), r"""&#8217;""", str)
-	str = re.sub(r"""^"(?=%s\\B)""" % (punct_class,), r"""&#8221;""", str)
-
-	# Special case for double sets of quotes, e.g.:
-	#   <p>He said, "'Quoted' words in a larger quote."</p>
-	str = re.sub(r""""'(?=\w)""", """&#8220;&#8216;""", str)
-	str = re.sub(r"""'"(?=\w)""", """&#8216;&#8220;""", str)
-
-	# Special case for decade abbreviations (the '80s):
-	str = re.sub(r"""\b'(?=\d{2}s)""", r"""&#8217;""", str)
-
-	close_class = r"""[^\ \t\r\n\[\{\(\-]"""
-	dec_dashes = r"""&#8211;|&#8212;"""
-
-	# Get most opening single quotes:
-	opening_single_quotes_regex = re.compile(r"""
-			(
-				\s          |   # a whitespace char, or
-				&nbsp;      |   # a non-breaking space entity, or
-				--          |   # dashes, or
-				&[mn]dash;  |   # named dash entities
-				%s          |   # or decimal entities
-				&\#x201[34];    # or hex
-			)
-			'                 # the quote
-			(?=\w)            # followed by a word character
-			""" % (dec_dashes,), re.VERBOSE)
-	str = opening_single_quotes_regex.sub(r"""\1&#8216;""", str)
-
-	closing_single_quotes_regex = re.compile(r"""
-			(%s)
-			'
-			(?!\s | s\b | \d)
-			""" % (close_class,), re.VERBOSE)
-	str = closing_single_quotes_regex.sub(r"""\1&#8217;""", str)
-
-	closing_single_quotes_regex = re.compile(r"""
-			(%s)
-			'
-			(\s | s\b)
-			""" % (close_class,), re.VERBOSE)
-	str = closing_single_quotes_regex.sub(r"""\1&#8217;\2""", str)
-
-	# Any remaining single quotes should be opening ones:
-	str = re.sub(r"""'""", r"""&#8216;""", str)
-
-	# Get most opening double quotes:
-	opening_double_quotes_regex = re.compile(r"""
-			(
-				\s          |   # a whitespace char, or
-				&nbsp;      |   # a non-breaking space entity, or
-				--          |   # dashes, or
-				&[mn]dash;  |   # named dash entities
-				%s          |   # or decimal entities
-				&\#x201[34];    # or hex
-			)
-			"                 # the quote
-			(?=\w)            # followed by a word character
-			""" % (dec_dashes,), re.VERBOSE)
-	str = opening_double_quotes_regex.sub(r"""\1&#8220;""", str)
-
-	# Double closing quotes:
-	closing_double_quotes_regex = re.compile(r"""
-			#(%s)?   # character that indicates the quote should be closing
-			"
-			(?=\s)
-			""" % (close_class,), re.VERBOSE)
-	str = closing_double_quotes_regex.sub(r"""&#8221;""", str)
-
-	closing_double_quotes_regex = re.compile(r"""
-			(%s)   # character that indicates the quote should be closing
-			"
-			""" % (close_class,), re.VERBOSE)
-	str = closing_double_quotes_regex.sub(r"""\1&#8221;""", str)
-
-	# Any remaining quotes should be opening ones.
-	str = re.sub(r'"', r"""&#8220;""", str)
-
-	return str
-
-
-def educateBackticks(str):
-	"""
-	Parameter:  String.
-	Returns:    The string, with ``backticks'' -style double quotes
-	            translated into HTML curly quote entities.
-	Example input:  ``Isn't this fun?''
-	Example output: &#8220;Isn't this fun?&#8221;
-	"""
-
-	str = re.sub(r"""``""", r"""&#8220;""", str)
-	str = re.sub(r"""''""", r"""&#8221;""", str)
-	return str
-
-
-def educateSingleBackticks(str):
-	"""
-	Parameter:  String.
-	Returns:    The string, with `backticks' -style single quotes
-	            translated into HTML curly quote entities.
-	
-	Example input:  `Isn't this fun?'
-	Example output: &#8216;Isn&#8217;t this fun?&#8217;
-	"""
-
-	str = re.sub(r"""`""", r"""&#8216;""", str)
-	str = re.sub(r"""'""", r"""&#8217;""", str)
-	return str
-
-
-def educateDashes(str):
-	"""
-	Parameter:  String.
-	
-	Returns:    The string, with each instance of "--" translated to
-	            an em-dash HTML entity.
-	"""
-
-	str = re.sub(r"""---""", r"""&#8211;""", str) # en  (yes, backwards)
-	str = re.sub(r"""--""", r"""&#8212;""", str) # em (yes, backwards)
-	return str
-
-
-def educateDashesOldSchool(str):
-	"""
-	Parameter:  String.
-	
-	Returns:    The string, with each instance of "--" translated to
-	            an en-dash HTML entity, and each "---" translated to
-	            an em-dash HTML entity.
-	"""
-
-	str = re.sub(r"""---""", r"""&#8212;""", str)    # em (yes, backwards)
-	str = re.sub(r"""--""", r"""&#8211;""", str)    # en (yes, backwards)
-	return str
-
-
-def educateDashesOldSchoolInverted(str):
-	"""
-	Parameter:  String.
-	
-	Returns:    The string, with each instance of "--" translated to
-	            an em-dash HTML entity, and each "---" translated to
-	            an en-dash HTML entity. Two reasons why: First, unlike the
-	            en- and em-dash syntax supported by
-	            EducateDashesOldSchool(), it's compatible with existing
-	            entries written before SmartyPants 1.1, back when "--" was
-	            only used for em-dashes.  Second, em-dashes are more
-	            common than en-dashes, and so it sort of makes sense that
-	            the shortcut should be shorter to type. (Thanks to Aaron
-	            Swartz for the idea.)
-	"""
-	str = re.sub(r"""---""", r"""&#8211;""", str)    # em
-	str = re.sub(r"""--""", r"""&#8212;""", str)    # en
-	return str
-
-
-
-def educateEllipses(str):
-	"""
-	Parameter:  String.
-	Returns:    The string, with each instance of "..." translated to
-	            an ellipsis HTML entity.
-	
-	Example input:  Huh...?
-	Example output: Huh&#8230;?
-	"""
-
-	str = re.sub(r"""\.\.\.""", r"""&#8230;""", str)
-	str = re.sub(r"""\. \. \.""", r"""&#8230;""", str)
-	return str
-
-
-def stupefyEntities(str):
-	"""
-	Parameter:  String.
-	Returns:    The string, with each SmartyPants HTML entity translated to
-	            its ASCII counterpart.
-
-	Example input:  &#8220;Hello &#8212; world.&#8221;
-	Example output: "Hello -- world."
-	"""
-
-	str = re.sub(r"""&#8211;""", r"""-""", str)  # en-dash
-	str = re.sub(r"""&#8212;""", r"""--""", str) # em-dash
-
-	str = re.sub(r"""&#8216;""", r"""'""", str)  # open single quote
-	str = re.sub(r"""&#8217;""", r"""'""", str)  # close single quote
-
-	str = re.sub(r"""&#8220;""", r'''"''', str)  # open double quote
-	str = re.sub(r"""&#8221;""", r'''"''', str)  # close double quote
-
-	str = re.sub(r"""&#8230;""", r"""...""", str)# ellipsis
-
-	return str
-
-
-def processEscapes(str):
-	r"""
-	Parameter:  String.
-	Returns:    The string, with after processing the following backslash
-	            escape sequences. This is useful if you want to force a "dumb"
-	            quote or other character to appear.
-	
-	            Escape  Value
-	            ------  -----
-	            \\      &#92;
-	            \"      &#34;
-	            \'      &#39;
-	            \.      &#46;
-	            \-      &#45;
-	            \`      &#96;
-	"""
-	str = re.sub(r"""\\\\""", r"""&#92;""", str)
-	str = re.sub(r'''\\"''', r"""&#34;""", str)
-	str = re.sub(r"""\\'""", r"""&#39;""", str)
-	str = re.sub(r"""\\\.""", r"""&#46;""", str)
-	str = re.sub(r"""\\-""", r"""&#45;""", str)
-	str = re.sub(r"""\\`""", r"""&#96;""", str)
-
-	return str
-
-
-def _tokenize(str):
-	"""
-	Parameter:  String containing HTML markup.
-	Returns:    Reference to an array of the tokens comprising the input
-	            string. Each token is either a tag (possibly with nested,
-	            tags contained therein, such as <a href="<MTFoo>">, or a
-	            run of text between tags. Each element of the array is a
-	            two-element array; the first is either 'tag' or 'text';
-	            the second is the actual value.
-	
-	Based on the _tokenize() subroutine from Brad Choate's MTRegex plugin.
-	    <http://www.bradchoate.com/past/mtregex.php>
-	"""
-
-	pos = 0
-	length = len(str)
-	tokens = []
-
-	depth = 6
-	nested_tags = "|".join(['(?:<(?:[^<>]',] * depth) + (')*>)' * depth)
-	#match = r"""(?: <! ( -- .*? -- \s* )+ > ) |  # comments
-	#		(?: <\? .*? \?> ) |  # directives
-	#		%s  # nested tags       """ % (nested_tags,)
-	tag_soup = re.compile(r"""([^<]*)(<[^>]*>)""")
-
-	token_match = tag_soup.search(str)
-
-	previous_end = 0
-	while token_match is not None:
-		if token_match.group(1):
-			tokens.append(['text', token_match.group(1)])
-
-		tokens.append(['tag', token_match.group(2)])
-
-		previous_end = token_match.end()
-		token_match = tag_soup.search(str, token_match.end())
-
-	if previous_end < len(str):
-		tokens.append(['text', str[previous_end:]])
-
-	return tokens
-
-
-
-if __name__ == "__main__":
-
-	import locale
-
-	try:
-		locale.setlocale(locale.LC_ALL, '')
-	except:
-		pass
-
-	from docutils.core import publish_string
-	docstring_html = publish_string(__doc__, writer_name='html')
-
-	print docstring_html
-
-
-	# Unit test output goes out stderr.  No worries.
-	import unittest
-	sp = smartyPants
-
-	class TestSmartypantsAllAttributes(unittest.TestCase):
-		# the default attribute is "1", which means "all".
-
-		def test_dates(self):
-			self.assertEqual(sp("1440-80's"), "1440-80&#8217;s")
-			self.assertEqual(sp("1440-'80s"), "1440-&#8216;80s")
-			self.assertEqual(sp("1440---'80s"), "1440&#8211;&#8216;80s")
-			self.assertEqual(sp("1960s"), "1960s")  # no effect.
-			self.assertEqual(sp("1960's"), "1960&#8217;s")
-			self.assertEqual(sp("one two '60s"), "one two &#8216;60s")
-			self.assertEqual(sp("'60s"), "&#8216;60s")
-
-		def test_skip_tags(self):
-			self.assertEqual(
-				sp("""<script type="text/javascript">\n<!--\nvar href = "http://www.google.com";\nvar linktext = "google";\ndocument.write('<a href="' + href + '">' + linktext + "</a>");\n//-->\n</script>"""), 
-				   """<script type="text/javascript">\n<!--\nvar href = "http://www.google.com";\nvar linktext = "google";\ndocument.write('<a href="' + href + '">' + linktext + "</a>");\n//-->\n</script>""")
-			self.assertEqual(
-				sp("""<p>He said &quot;Let's write some code.&quot; This code here <code>if True:\n\tprint &quot;Okay&quot;</code> is python code.</p>"""), 
-				   """<p>He said &#8220;Let&#8217;s write some code.&#8221; This code here <code>if True:\n\tprint &quot;Okay&quot;</code> is python code.</p>""")
-
-
-		def test_ordinal_numbers(self):
-			self.assertEqual(sp("21st century"), "21st century")  # no effect.
-			self.assertEqual(sp("3rd"), "3rd")  # no effect.
-
-		def test_educated_quotes(self):
-			self.assertEqual(sp('''"Isn't this fun?"'''), '''&#8220;Isn&#8217;t this fun?&#8221;''')
-
-	unittest.main()
-
-
-
-
-__author__ = "Chad Miller <smartypantspy@chad.org>"
-__version__ = "1.5_1.6: Fri, 27 Jul 2007 07:06:40 -0400"
-__url__ = "http://wiki.chad.org/SmartyPantsPy"
-__description__ = "Smart-quotes, smart-ellipses, and smart-dashes for weblog entries in pyblosxom"
diff --git a/lib/webob/__init__.py b/lib/webob/__init__.py
@@ -1,2383 +0,0 @@
-from cStringIO import StringIO
-import sys
-import cgi
-import urllib
-import urlparse
-import re
-import textwrap
-from Cookie import BaseCookie
-from rfc822 import parsedate_tz, mktime_tz, formatdate
-from datetime import datetime, date, timedelta, tzinfo
-import time
-import calendar
-import tempfile
-import warnings
-from webob.datastruct import EnvironHeaders
-from webob.multidict import MultiDict, UnicodeMultiDict, NestedMultiDict, NoVars
-from webob.etag import AnyETag, NoETag, ETagMatcher, IfRange, NoIfRange
-from webob.headerdict import HeaderDict
-from webob.statusreasons import status_reasons
-from webob.cachecontrol import CacheControl, serialize_cache_control
-from webob.acceptparse import Accept, MIMEAccept, NilAccept, MIMENilAccept, NoAccept
-from webob.byterange import Range, ContentRange
-try:
-    sorted
-except NameError:
-    from webob.compat import sorted
-
-_CHARSET_RE = re.compile(r';\s*charset=([^;]*)', re.I)
-_SCHEME_RE = re.compile(r'^[a-z]+:', re.I)
-_PARAM_RE = re.compile(r'([a-z0-9]+)=(?:"([^"]*)"|([a-z0-9_.-]*))', re.I)
-_OK_PARAM_RE = re.compile(r'^[a-z0-9_.-]+$', re.I)
-
-__all__ = ['Request', 'Response', 'UTC', 'day', 'week', 'hour', 'minute', 'second', 'month', 'year', 'html_escape']
-
-class _UTC(tzinfo):
-    def dst(self, dt):
-        return timedelta(0)
-    def utcoffset(self, dt):
-        return timedelta(0)
-    def tzname(self, dt):
-        return 'UTC'
-    def __repr__(self):
-        return 'UTC'
-
-UTC = _UTC()
-
-def html_escape(s):
-    """HTML-escape a string or object
-
-    This converts any non-string objects passed into it to strings
-    (actually, using ``unicode()``).  All values returned are
-    non-unicode strings (using ``&#num;`` entities for all non-ASCII
-    characters).
-
-    None is treated specially, and returns the empty string.
-    """
-    if s is None:
-        return ''
-    if not isinstance(s, basestring):
-        if hasattr(s, '__unicode__'):
-            s = unicode(s)
-        else:
-            s = str(s)
-    s = cgi.escape(s, True)
-    if isinstance(s, unicode):
-        s = s.encode('ascii', 'xmlcharrefreplace')
-    return s
-
-def timedelta_to_seconds(td):
-    """
-    Converts a timedelta instance to seconds.
-    """
-    return td.seconds + (td.days*24*60*60)
-
-day = timedelta(days=1)
-week = timedelta(weeks=1)
-hour = timedelta(hours=1)
-minute = timedelta(minutes=1)
-second = timedelta(seconds=1)
-# Estimate, I know; good enough for expirations
-month = timedelta(days=30)
-year = timedelta(days=365)
-
-class _NoDefault:
-    def __repr__(self):
-        return '(No Default)'
-NoDefault = _NoDefault()
-
-class environ_getter(object):
-    """For delegating an attribute to a key in self.environ."""
-
-    def __init__(self, key, default='', default_factory=None,
-                 settable=True, deletable=True, doc=None,
-                 rfc_section=None):
-        self.key = key
-        self.default = default
-        self.default_factory = default_factory
-        self.settable = settable
-        self.deletable = deletable
-        docstring = "Gets"
-        if self.settable:
-            docstring += " and sets"
-        if self.deletable:
-            docstring += " and deletes"
-        docstring += " the %r key from the environment." % self.key
-        docstring += _rfc_reference(self.key, rfc_section)
-        if doc:
-            docstring += '\n\n' + textwrap.dedent(doc)
-        self.__doc__ = docstring
-
-    def __get__(self, obj, type=None):
-        if obj is None:
-            return self
-        if self.key not in obj.environ:
-            if self.default_factory:
-                val = obj.environ[self.key] = self.default_factory()
-                return val
-            else:
-                return self.default
-        return obj.environ[self.key]
-
-    def __set__(self, obj, value):
-        if not self.settable:
-            raise AttributeError("Read-only attribute (key %r)" % self.key)
-        if value is None:
-            if self.key in obj.environ:
-                del obj.environ[self.key]
-        else:
-            obj.environ[self.key] = value
-
-    def __delete__(self, obj):
-        if not self.deletable:
-            raise AttributeError("You cannot delete the key %r" % self.key)
-        del obj.environ[self.key]
-
-    def __repr__(self):
-        return '<Proxy for WSGI environ %r key>' % self.key
-
-class header_getter(object):
-    """For delegating an attribute to a header in self.headers"""
-
-    def __init__(self, header, default=None,
-                 settable=True, deletable=True, doc=None, rfc_section=None):
-        self.header = header
-        self.default = default
-        self.settable = settable
-        self.deletable = deletable
-        docstring = "Gets"
-        if self.settable:
-            docstring += " and sets"
-        if self.deletable:
-            docstring += " and deletes"
-        docstring += " they header %s from the headers" % self.header
-        docstring += _rfc_reference(self.header, rfc_section)
-        if doc:
-            docstring += '\n\n' + textwrap.dedent(doc)
-        self.__doc__ = docstring
-
-    def __get__(self, obj, type=None):
-        if obj is None:
-            return self
-        if self.header not in obj.headers:
-            return self.default
-        else:
-            return obj.headers[self.header]
-
-    def __set__(self, obj, value):
-        if not self.settable:
-            raise AttributeError("Read-only attribute (header %s)" % self.header)
-        if value is None:
-            if self.header in obj.headers:
-                del obj.headers[self.header]
-        else:
-            if isinstance(value, unicode):
-                # This is the standard encoding for headers:
-                value = value.encode('ISO-8859-1')
-            obj.headers[self.header] = value
-
-    def __delete__(self, obj):
-        if not self.deletable:
-            raise AttributeError("You cannot delete the header %s" % self.header)
-        del obj.headers[self.header]
-
-    def __repr__(self):
-        return '<Proxy for header %s>' % self.header
-
-class converter(object):
-    """
-    Wraps a decorator, and applies conversion for that decorator
-    """
-    def __init__(self, decorator, getter_converter, setter_converter, convert_name=None, doc=None, converter_args=()):
-        self.decorator = decorator
-        self.getter_converter = getter_converter
-        self.setter_converter = setter_converter
-        self.convert_name = convert_name
-        self.converter_args = converter_args
-        docstring = decorator.__doc__ or ''
-        docstring += "  Converts it as a "
-        if convert_name:
-            docstring += convert_name + '.'
-        else:
-            docstring += "%r and %r." % (getter_converter, setter_converter)
-        if doc:
-            docstring += '\n\n' + textwrap.dedent(doc)
-        self.__doc__ = docstring
-
-    def __get__(self, obj, type=None):
-        if obj is None:
-            return self
-        value = self.decorator.__get__(obj, type)
-        return self.getter_converter(value, *self.converter_args)
-
-    def __set__(self, obj, value):
-        value = self.setter_converter(value, *self.converter_args)
-        self.decorator.__set__(obj, value)
-
-    def __delete__(self, obj):
-        self.decorator.__delete__(obj)
-
-    def __repr__(self):
-        if self.convert_name:
-            name = ' %s' % self.convert_name
-        else:
-            name = ''
-        return '<Converted %r%s>' % (self.decorator, name)
-
-def _rfc_reference(header, section):
-    if not section:
-        return ''
-    major_section = section.split('.')[0]
-    link = 'http://www.w3.org/Protocols/rfc2616/rfc2616-sec%s.html#sec%s' % (
-        major_section, section)
-    if header.startswith('HTTP_'):
-        header = header[5:].title().replace('_', '-')
-    return "  For more information on %s see `section %s <%s>`_." % (
-        header, section, link)
-
-class deprecated_property(object):
-    """
-    Wraps a decorator, with a deprecation warning or error
-    """
-    def __init__(self, decorator, attr, message, warning=True):
-        self.decorator = decorator
-        self.attr = attr
-        self.message = message
-        self.warning = warning
-
-    def __get__(self, obj, type=None):
-        if obj is None:
-            return self
-        self.warn()
-        return self.decorator.__get__(obj, type)
-
-    def __set__(self, obj, value):
-        self.warn()
-        self.decorator.__set__(obj, value)
-
-    def __delete__(self, obj):
-        self.warn()
-        self.decorator.__delete__(obj)
-
-    def __repr__(self):
-        return '<Deprecated attribute %s: %r>' % (
-            self.attr,
-            self.decorator)
-
-    def warn(self):
-        if not self.warning:
-            raise DeprecationWarning(
-                'The attribute %s is deprecated: %s' % (self.attr, self.message))
-        else:
-            warnings.warn(
-                'The attribute %s is deprecated: %s' % (self.attr, self.message),
-                DeprecationWarning,
-                stacklevel=3)
-
-def _parse_date(value):
-    if not value:
-        return None
-    t = parsedate_tz(value)
-    if t is None:
-        # Could not parse
-        return None
-    if t[-1] is None:
-        # No timezone given.  None would mean local time, but we'll force UTC
-        t = t[:9] + (0,)
-    t = mktime_tz(t)
-    return datetime.fromtimestamp(t, UTC)
-
-def _serialize_date(dt):
-    if dt is None:
-        return None
-    if isinstance(dt, unicode):
-        dt = dt.encode('ascii')
-    if isinstance(dt, str):
-        return dt
-    if isinstance(dt, timedelta):
-        dt = datetime.now() + dt
-    if isinstance(dt, (datetime, date)):
-        dt = dt.timetuple()
-    if isinstance(dt, (tuple, time.struct_time)):
-        dt = calendar.timegm(dt)
-    if not isinstance(dt, (float, int, long)):
-        raise ValueError(
-            "You must pass in a datetime, date, time tuple, or integer object, not %r" % dt)
-    return formatdate(dt)
-
-def _serialize_cookie_date(dt):
-    if dt is None:
-        return None
-    if isinstance(dt, unicode):
-        dt = dt.encode('ascii')
-    if isinstance(dt, timedelta):
-        dt = datetime.now() + dt
-    if isinstance(dt, (datetime, date)):
-        dt = dt.timetuple()
-    return time.strftime('%a, %d-%b-%Y %H:%M:%S GMT', dt)
-
-def _parse_date_delta(value):
-    """
-    like _parse_date, but also handle delta seconds
-    """
-    if not value:
-        return None
-    try:
-        value = int(value)
-    except ValueError:
-        pass
-    else:
-        delta = timedelta(seconds=value)
-        return datetime.now() + delta
-    return _parse_date(value)
-
-def _serialize_date_delta(value):
-    if not value and value != 0:
-        return None
-    if isinstance(value, (float, int)):
-        return str(int(value))
-    return _serialize_date(value)
-
-def _parse_etag(value, default=True):
-    if value is None:
-        value = ''
-    value = value.strip()
-    if not value:
-        if default:
-            return AnyETag
-        else:
-            return NoETag
-    if value == '*':
-        return AnyETag
-    else:
-        return ETagMatcher.parse(value)
-
-def _serialize_etag(value, default=True):
-    if value is None:
-        return None
-    if value is AnyETag:
-        if default:
-            return None
-        else:
-            return '*'
-    return str(value)
-
-def _parse_if_range(value):
-    if not value:
-        return NoIfRange
-    else:
-        return IfRange.parse(value)
-
-def _serialize_if_range(value):
-    if value is None:
-        return value
-    if isinstance(value, (datetime, date)):
-        return _serialize_date(value)
-    if not isinstance(value, str):
-        value = str(value)
-    return value or None
-
-def _parse_range(value):
-    if not value:
-        return None
-    # Might return None too:
-    return Range.parse(value)
-
-def _serialize_range(value):
-    if isinstance(value, (list, tuple)):
-        if len(value) != 2:
-            raise ValueError(
-                "If setting .range to a list or tuple, it must be of length 2 (not %r)"
-                % value)
-        value = Range([value])
-    if value is None:
-        return None
-    value = str(value)
-    return value or None
-
-def _parse_int(value):
-    if value is None or value == '':
-        return None
-    return int(value)
-
-def _parse_int_safe(value):
-    if value is None or value == '':
-        return None
-    try:
-        return int(value)
-    except ValueError:
-        return None
-
-def _serialize_int(value):
-    if value is None:
-        return None
-    return str(value)
-
-def _parse_content_range(value):
-    if not value or not value.strip():
-        return None
-    # May still return None
-    return ContentRange.parse(value)
-
-def _serialize_content_range(value):
-    if value is None:
-        return None
-    if isinstance(value, (tuple, list)):
-        if len(value) not in (2, 3):
-            raise ValueError(
-                "When setting content_range to a list/tuple, it must "
-                "be length 2 or 3 (not %r)" % value)
-        if len(value) == 2:
-            begin, end = value
-            length = None
-        else:
-            begin, end, length = value
-        value = ContentRange(begin, end, length)
-    value = str(value).strip()
-    if not value:
-        return None
-    return value
-
-def _parse_list(value):
-    if value is None:
-        return None
-    value = value.strip()
-    if not value:
-        return None
-    return [v.strip() for v in value.split(',')
-            if v.strip()]
-
-def _serialize_list(value):
-    if not value:
-        return None
-    if isinstance(value, unicode):
-        value = str(value)
-    if isinstance(value, str):
-        return value
-    return ', '.join(map(str, value))
-
-def _parse_accept(value, header_name, AcceptClass, NilClass):
-    if not value:
-        return NilClass(header_name)
-    return AcceptClass(header_name, value)
-
-def _serialize_accept(value, header_name, AcceptClass, NilClass):
-    if not value or isinstance(value, NilClass):
-        return None
-    if isinstance(value, (list, tuple, dict)):
-        value = NilClass(header_name) + value
-    value = str(value).strip()
-    if not value:
-        return None
-    return value
-
-class Request(object):
-
-    ## Options:
-    charset = None
-    unicode_errors = 'strict'
-    decode_param_names = False
-    ## The limit after which request bodies should be stored on disk
-    ## if they are read in (under this, and the request body is stored
-    ## in memory):
-    request_body_tempfile_limit = 10*1024
-
-    def __init__(self, environ=None, environ_getter=None, charset=NoDefault, unicode_errors=NoDefault,
-                 decode_param_names=NoDefault, **kw):
-        if environ is None and environ_getter is None:
-            raise TypeError(
-                "You must provide one of environ or environ_getter")
-        if environ is not None and environ_getter is not None:
-            raise TypeError(
-                "You can only provide one of the environ and environ_getter arguments")
-        if environ is None:
-            self._environ_getter = environ_getter
-        else:
-            if not isinstance(environ, dict):
-                raise TypeError(
-                    "Bad type for environ: %s" % type(environ))
-            self._environ = environ
-        if charset is not NoDefault:
-            self.__dict__['charset'] = charset
-        if unicode_errors is not NoDefault:
-            self.__dict__['unicode_errors'] = unicode_errors
-        if decode_param_names is not NoDefault:
-            self.__dict__['decode_param_names'] = decode_param_names
-        for name, value in kw.items():
-            if not hasattr(self.__class__, name):
-                raise TypeError(
-                    "Unexpected keyword: %s=%r" % name, value)
-            setattr(self, name, value)
-
-    def __setattr__(self, attr, value, DEFAULT=[]):
-        ## FIXME: I don't know why I need this guard (though experimentation says I do)
-        if getattr(self.__class__, attr, DEFAULT) is not DEFAULT or attr.startswith('_'):
-            object.__setattr__(self, attr, value)
-        else:
-            self.environ.setdefault('webob.adhoc_attrs', {})[attr] = value
-
-    def __getattr__(self, attr):
-        ## FIXME: I don't know why I need this guard (though experimentation says I do)
-        if attr in self.__class__.__dict__:
-            return object.__getattribute__(self, attr)
-        try:
-            return self.environ['webob.adhoc_attrs'][attr]
-        except KeyError:
-            raise AttributeError(attr)
-
-    def __delattr__(self, attr):
-        ## FIXME: I don't know why I need this guard (though experimentation says I do)
-        if attr in self.__class__.__dict__:
-            return object.__delattr__(self, attr)
-        try:
-            del self.environ['webob.adhoc_attrs'][attr]
-        except KeyError:
-            raise AttributeError(attr)
-
-    def environ(self):
-        """
-        The WSGI environment dictionary for this request
-        """
-        return self._environ_getter()
-    environ = property(environ, doc=environ.__doc__)
-
-    def _environ_getter(self):
-        return self._environ
-
-    def _body_file__get(self):
-        """
-        Access the body of the request (wsgi.input) as a file-like
-        object.
-
-        If you set this value, CONTENT_LENGTH will also be updated
-        (either set to -1, 0 if you delete the attribute, or if you
-        set the attribute to a string then the length of the string).
-        """
-        return self.environ['wsgi.input']
-    def _body_file__set(self, value):
-        if isinstance(value, str):
-            length = len(value)
-            value = StringIO(value)
-        else:
-            length = -1
-        self.environ['wsgi.input'] = value
-        self.environ['CONTENT_LENGTH'] = str(length)
-    def _body_file__del(self):
-        self.environ['wsgi.input'] = StringIO('')
-        self.environ['CONTENT_LENGTH'] = '0'
-    body_file = property(_body_file__get, _body_file__set, _body_file__del, doc=_body_file__get.__doc__)
-
-    scheme = environ_getter('wsgi.url_scheme')
-    method = environ_getter('REQUEST_METHOD')
-    script_name = environ_getter('SCRIPT_NAME')
-    path_info = environ_getter('PATH_INFO')
-    ## FIXME: should I strip out parameters?:
-    content_type = environ_getter('CONTENT_TYPE', rfc_section='14.17')
-    content_length = converter(
-        environ_getter('CONTENT_LENGTH', rfc_section='14.13'),
-        _parse_int_safe, _serialize_int, 'int')
-    remote_user = environ_getter('REMOTE_USER', default=None)
-    remote_addr = environ_getter('REMOTE_ADDR', default=None)
-    query_string = environ_getter('QUERY_STRING')
-    server_name = environ_getter('SERVER_NAME')
-    server_port = converter(
-        environ_getter('SERVER_PORT'),
-        _parse_int, _serialize_int, 'int')
-
-    _headers = None
-
-    def _headers__get(self):
-        """
-        All the request headers as a case-insensitive dictionary-like
-        object.
-        """
-        if self._headers is None:
-            self._headers = EnvironHeaders(self.environ)
-        return self._headers
-
-    def _headers__set(self, value):
-        self.headers.clear()
-        self.headers.update(value)
-
-    headers = property(_headers__get, _headers__set, doc=_headers__get.__doc__)
-
-    def host_url(self):
-        """
-        The URL through the host (no path)
-        """
-        e = self.environ
-        url = e['wsgi.url_scheme'] + '://'
-        if e.get('HTTP_HOST'):
-            host = e['HTTP_HOST']
-            if ':' in host:
-                host, port = host.split(':', 1)
-            else:
-
-                port = None
-        else:
-            host = e['SERVER_NAME']
-            port = e['SERVER_PORT']
-        if self.environ['wsgi.url_scheme'] == 'https':
-            if port == '443':
-                port = None
-        elif self.environ['wsgi.url_scheme'] == 'http':
-            if port == '80':
-                port = None
-        url += host
-        if port:
-            url += ':%s' % port
-        return url
-    host_url = property(host_url, doc=host_url.__doc__)
-
-    def application_url(self):
-        """
-        The URL including SCRIPT_NAME (no PATH_INFO or query string)
-        """
-        return self.host_url + urllib.quote(self.environ.get('SCRIPT_NAME', ''))
-    application_url = property(application_url, doc=application_url.__doc__)
-
-    def path_url(self):
-        """
-        The URL including SCRIPT_NAME and PATH_INFO, but not QUERY_STRING
-        """
-        return self.application_url + urllib.quote(self.environ.get('PATH_INFO', ''))
-    path_url = property(path_url, doc=path_url.__doc__)
-
-    def path(self):
-        """
-        The path of the request, without host or query string
-        """
-        return urllib.quote(self.script_name) + urllib.quote(self.path_info)
-    path = property(path, doc=path.__doc__)
-
-    def path_qs(self):
-        """
-        The path of the request, without host but with query string
-        """
-        path = self.path
-        qs = self.environ.get('QUERY_STRING')
-        if qs:
-            path += '?' + qs
-        return path
-    path_qs = property(path_qs, doc=path_qs.__doc__)
-
-    def url(self):
-        """
-        The full request URL, including QUERY_STRING
-        """
-        url = self.path_url
-        if self.environ.get('QUERY_STRING'):
-            url += '?' + self.environ['QUERY_STRING']
-        return url
-    url = property(url, doc=url.__doc__)
-
-    def relative_url(self, other_url, to_application=False):
-        """
-        Resolve other_url relative to the request URL.
-
-        If ``to_application`` is True, then resolve it relative to the
-        URL with only SCRIPT_NAME
-        """
-        if to_application:
-            url = self.application_url
-            if not url.endswith('/'):
-                url += '/'
-        else:
-            url = self.path_url
-        return urlparse.urljoin(url, other_url)
-
-    def path_info_pop(self):
-        """
-        'Pops' off the next segment of PATH_INFO, pushing it onto
-        SCRIPT_NAME, and returning the popped segment.  Returns None if
-        there is nothing left on PATH_INFO.
-
-        Does not return ``''`` when there's an empty segment (like
-        ``/path//path``); these segments are just ignored.
-        """
-        path = self.path_info
-        if not path:
-            return None
-        while path.startswith('/'):
-            self.script_name += '/'
-            path = path[1:]
-        if '/' not in path:
-            self.script_name += path
-            self.path_info = ''
-            return path
-        else:
-            segment, path = path.split('/', 1)
-            self.path_info = '/' + path
-            self.script_name += segment
-            return segment
-
-    def path_info_peek(self):
-        """
-        Returns the next segment on PATH_INFO, or None if there is no
-        next segment.  Doesn't modify the environment.
-        """
-        path = self.path_info
-        if not path:
-            return None
-        path = path.lstrip('/')
-        return path.split('/', 1)[0]
-
-    def _urlvars__get(self):
-        """
-        Return any *named* variables matched in the URL.
-
-        Takes values from ``environ['wsgiorg.routing_args']``.
-        Systems like ``routes`` set this value.
-        """
-        if 'paste.urlvars' in self.environ:
-            return self.environ['paste.urlvars']
-        elif 'wsgiorg.routing_args' in self.environ:
-            return self.environ['wsgiorg.routing_args'][1]
-        else:
-            result = {}
-            self.environ['wsgiorg.routing_args'] = ((), result)
-            return result
-
-    def _urlvars__set(self, value):
-        environ = self.environ
-        if 'wsgiorg.routing_args' in environ:
-            environ['wsgiorg.routing_args'] = (environ['wsgiorg.routing_args'][0], value)
-            if 'paste.urlvars' in environ:
-                del environ['paste.urlvars']
-        elif 'paste.urlvars' in environ:
-            environ['paste.urlvars'] = value
-        else:
-            environ['wsgiorg.routing_args'] = ((), value)
-
-    def _urlvars__del(self):
-        if 'paste.urlvars' in self.environ:
-            del self.environ['paste.urlvars']
-        if 'wsgiorg.routing_args' in self.environ:
-            if not self.environ['wsgiorg.routing_args'][0]:
-                del self.environ['wsgiorg.routing_args']
-            else:
-                self.environ['wsgiorg.routing_args'] = (self.environ['wsgiorg.routing_args'][0], {})
-
-    urlvars = property(_urlvars__get, _urlvars__set, _urlvars__del, doc=_urlvars__get.__doc__)
-
-    def _urlargs__get(self):
-        """
-        Return any *positional* variables matched in the URL.
-
-        Takes values from ``environ['wsgiorg.routing_args']``.
-        Systems like ``routes`` set this value.
-        """
-        if 'wsgiorg.routing_args' in self.environ:
-            return self.environ['wsgiorg.routing_args'][0]
-        else:
-            # Since you can't update this value in-place, we don't need
-            # to set the key in the environment
-            return ()
-
-    def _urlargs__set(self, value):
-        environ = self.environ
-        if 'paste.urlvars' in environ:
-            # Some overlap between this and wsgiorg.routing_args; we need
-            # wsgiorg.routing_args to make this work
-            routing_args = (value, environ.pop('paste.urlvars'))
-        elif 'wsgiorg.routing_args' in environ:
-            routing_args = (value, environ['wsgiorg.routing_args'][1])
-        else:
-            routing_args = (value, {})
-        environ['wsgiorg.routing_args'] = routing_args
-
-    def _urlargs__del(self):
-        if 'wsgiorg.routing_args' in self.environ:
-            if not self.environ['wsgiorg.routing_args'][1]:
-                del self.environ['wsgiorg.routing_args']
-            else:
-                self.environ['wsgiorg.routing_args'] = ((), self.environ['wsgiorg.routing_args'][1])
-
-    urlargs = property(_urlargs__get, _urlargs__set, _urlargs__del, _urlargs__get.__doc__)
-
-    def is_xhr(self):
-        """Returns a boolean if X-Requested-With is present and ``XMLHttpRequest``
-
-        Note: this isn't set by every XMLHttpRequest request, it is
-        only set if you are using a Javascript library that sets it
-        (or you set the header yourself manually).  Currently
-        Prototype and jQuery are known to set this header."""
-        return self.environ.get('HTTP_X_REQUESTED_WITH', '') == 'XMLHttpRequest'
-    is_xhr = property(is_xhr, doc=is_xhr.__doc__)
-
-    def _host__get(self):
-        """Host name provided in HTTP_HOST, with fall-back to SERVER_NAME"""
-        if 'HTTP_HOST' in self.environ:
-            return self.environ['HTTP_HOST']
-        else:
-            return '%(SERVER_NAME)s:%(SERVER_PORT)s' % self.environ
-    def _host__set(self, value):
-        self.environ['HTTP_HOST'] = value
-    def _host__del(self):
-        if 'HTTP_HOST' in self.environ:
-            del self.environ['HTTP_HOST']
-    host = property(_host__get, _host__set, _host__del, doc=_host__get.__doc__)
-
-    def _body__get(self):
-        """
-        Return the content of the request body.
-        """
-        try:
-            length = int(self.environ.get('CONTENT_LENGTH', '0'))
-        except ValueError:
-            return ''
-        c = self.body_file.read(length)
-        tempfile_limit = self.request_body_tempfile_limit
-        if tempfile_limit and len(c) > tempfile_limit:
-            fileobj = tempfile.TemporaryFile()
-            fileobj.write(c)
-            fileobj.seek(0)
-        else:
-            fileobj = StringIO(c)
-        # We don't want/need to lose CONTENT_LENGTH here (as setting
-        # self.body_file would do):
-        self.environ['wsgi.input'] = fileobj
-        return c
-
-    def _body__set(self, value):
-        if value is None:
-            del self.body
-            return
-        if not isinstance(value, str):
-            raise TypeError(
-                "You can only set Request.body to a str (not %r)" % type(value))
-        body_file = StringIO(value)
-        self.body_file = body_file
-        self.environ['CONTENT_LENGTH'] = str(len(value))
-
-    def _body__del(self, value):
-        del self.body_file
-
-    body = property(_body__get, _body__set, _body__del, doc=_body__get.__doc__)
-
-    def str_POST(self):
-        """
-        Return a MultiDict containing all the variables from a form
-        request. Returns an empty dict-like object for non-form
-        requests.
-
-        Form requests are typically POST requests, however PUT requests
-        with an appropriate Content-Type are also supported.
-        """
-        env = self.environ
-        if self.method not in ('POST', 'PUT'):
-            return NoVars('Not a form request')
-        if 'webob._parsed_post_vars' in env:
-            vars, body_file = env['webob._parsed_post_vars']
-            if body_file is self.body_file:
-                return vars
-        # Paste compatibility:
-        if 'paste.parsed_formvars' in env:
-            # from paste.request.parse_formvars
-            vars, body_file = env['paste.parsed_formvars']
-            if body_file is self.body_file:
-                # FIXME: is it okay that this isn't *our* MultiDict?
-                return vars
-        content_type = self.content_type
-        if ';' in content_type:
-            content_type = content_type.split(';', 1)[0]
-        if (self.method == 'PUT' and not content_type) or \
-                content_type not in ('', 'application/x-www-form-urlencoded',
-                                     'multipart/form-data'):
-            # Not an HTML form submission
-            return NoVars('Not an HTML form submission (Content-Type: %s)'
-                          % content_type)
-        if 'CONTENT_LENGTH' not in env:
-            # FieldStorage assumes a default CONTENT_LENGTH of -1, but a
-            # default of 0 is better:
-            env['CONTENT_TYPE'] = '0'
-        fs_environ = env.copy()
-        fs_environ['QUERY_STRING'] = ''
-        fs = cgi.FieldStorage(fp=self.body_file,
-                              environ=fs_environ,
-                              keep_blank_values=True)
-        vars = MultiDict.from_fieldstorage(fs)
-        FakeCGIBody.update_environ(env, vars)
-        env['webob._parsed_post_vars'] = (vars, self.body_file)
-        return vars
-
-    str_POST = property(str_POST, doc=str_POST.__doc__)
-
-    str_postvars = deprecated_property(str_POST, 'str_postvars',
-                                       'use str_POST instead')
-
-    def POST(self):
-        """
-        Like ``.str_POST``, but may decode values and keys
-        """
-        vars = self.str_POST
-        if self.charset:
-            vars = UnicodeMultiDict(vars, encoding=self.charset,
-                                    errors=self.unicode_errors,
-                                    decode_keys=self.decode_param_names)
-        return vars
-
-    POST = property(POST, doc=POST.__doc__)
-
-    postvars = deprecated_property(POST, 'postvars',
-                                   'use POST instead')
-
-    def str_GET(self):
-        """
-        Return a MultiDict containing all the variables from the
-        QUERY_STRING.
-        """
-        env = self.environ
-        source = env.get('QUERY_STRING', '')
-        if 'webob._parsed_query_vars' in env:
-            vars, qs = env['webob._parsed_query_vars']
-            if qs == source:
-                return vars
-        if not source:
-            vars = MultiDict()
-        else:
-            vars = MultiDict(cgi.parse_qsl(
-                source, keep_blank_values=True,
-                strict_parsing=False))
-        env['webob._parsed_query_vars'] = (vars, source)
-        return vars
-
-    str_GET = property(str_GET, doc=str_GET.__doc__)
-
-    str_queryvars = deprecated_property(str_GET, 'str_queryvars',
-                                        'use str_GET instead')
-
-
-    def GET(self):
-        """
-        Like ``.str_GET``, but may decode values and keys
-        """
-        vars = self.str_GET
-        if self.charset:
-            vars = UnicodeMultiDict(vars, encoding=self.charset,
-                                    errors=self.unicode_errors,
-                                    decode_keys=self.decode_param_names)
-        return vars
-
-    GET = property(GET, doc=GET.__doc__)
-
-    queryvars = deprecated_property(GET, 'queryvars',
-                                    'use GET instead')
-
-    def str_params(self):
-        """
-        A dictionary-like object containing both the parameters from
-        the query string and request body.
-        """
-        return NestedMultiDict(self.str_GET, self.str_POST)
-
-    str_params = property(str_params, doc=str_params.__doc__)
-
-    def params(self):
-        """
-        Like ``.str_params``, but may decode values and keys
-        """
-        params = self.str_params
-        if self.charset:
-            params = UnicodeMultiDict(params, encoding=self.charset,
-                                      errors=self.unicode_errors,
-                                      decode_keys=self.decode_param_names)
-        return params
-
-    params = property(params, doc=params.__doc__)
-
-    _rx_quotes = re.compile('"(.*)"')
-
-    def str_cookies(self):
-        """
-        Return a *plain* dictionary of cookies as found in the request.
-        """
-        env = self.environ
-        source = env.get('HTTP_COOKIE', '')
-        if 'webob._parsed_cookies' in env:
-            vars, var_source = env['webob._parsed_cookies']
-            if var_source == source:
-                return vars
-        vars = {}
-        if source:
-            cookies = BaseCookie()
-            cookies.load(source)
-            for name in cookies:
-                value = cookies[name].value
-                unquote_match = self._rx_quotes.match(value)
-                if unquote_match is not None:
-                    value = unquote_match.group(1)
-                vars[name] = value
-        env['webob._parsed_cookies'] = (vars, source)
-        return vars
-
-    str_cookies = property(str_cookies, doc=str_cookies.__doc__)
-
-    def cookies(self):
-        """
-        Like ``.str_cookies``, but may decode values and keys
-        """
-        vars = self.str_cookies
-        if self.charset:
-            vars = UnicodeMultiDict(vars, encoding=self.charset,
-                                    errors=self.unicode_errors,
-                                    decode_keys=self.decode_param_names)
-        return vars
-
-    cookies = property(cookies, doc=cookies.__doc__)
-
-    def copy(self):
-        """
-        Copy the request and environment object.
-
-        This only does a shallow copy, except of wsgi.input
-        """
-        env = self.environ.copy()
-        new_req = self.__class__(env)
-        new_req.copy_body()
-        return new_req
-
-    def copy_get(self):
-        """
-        Copies the request and environment object, but turning this request
-        into a GET along the way.  If this was a POST request (or any other verb)
-        then it becomes GET, and the request body is thrown away.
-        """
-        env = self.environ.copy()
-        env['wsgi.input'] = StringIO('')
-        env['CONTENT_LENGTH'] = '0'
-        if 'CONTENT_TYPE' in env:
-            del env['CONTENT_TYPE']
-        env['REQUEST_METHOD'] = 'GET'
-        return self.__class__(env)
-
-    def make_body_seekable(self):
-        """
-        This forces ``environ['wsgi.input']`` to be seekable.  That
-        is, if it doesn't have a `seek` method already, the content is
-        copied into a StringIO or temporary file.
-
-        The choice to copy to StringIO is made from
-        ``self.request_body_tempfile_limit``
-        """
-        input = self.body_file
-        if hasattr(input, 'seek'):
-            # It has a seek method, so we don't need to do anything
-            return
-        self.copy_body()
-
-    def copy_body(self):
-        """
-        Copies the body, in cases where it might be shared with
-        another request object and that is not desired.
-
-        This copies the body in-place, either into a StringIO object
-        or a temporary file.
-        """
-        length = self.content_length
-        if length == 0:
-            # No real need to copy this, but of course it is free
-            self.body_file = StringIO('')
-            return
-        tempfile_limit = self.request_body_tempfile_limit
-        body = None
-        input = self.body_file
-        if hasattr(input, 'seek'):
-            # Just in case someone has read parts of the body already
-            ## FIXME: Should we use .tell() to try to put the body
-            ## back to its previous position?
-            input.seek(0)
-        if length == -1:
-            body = self.body
-            length = len(body)
-            self.content_length = length
-        if tempfile_limit and length > tempfile_limit:
-            fileobj = tempfile.TemporaryFile()
-            if body is None:
-                while length:
-                    data = input.read(min(length, 4096))
-                    fileobj.write(data)
-                    length -= len(data)
-            else:
-                fileobj.write(body)
-            fileobj.seek(0)
-        else:
-            if body is None:
-                body = input.read(length)
-            fileobj = StringIO(body)
-        self.body_file = fileobj
-
-    def remove_conditional_headers(self, remove_encoding=True, remove_range=True,
-                                        remove_match=True, remove_modified=True):
-        """
-        Remove headers that make the request conditional.
-
-        These headers can cause the response to be 304 Not Modified,
-        which in some cases you may not want to be possible.
-
-        This does not remove headers like If-Match, which are used for
-        conflict detection.
-        """
-        check_keys = []
-        if remove_range:
-            check_keys += ['HTTP_IF_RANGE', 'HTTP_RANGE']
-        if remove_match:
-            check_keys.append('HTTP_IF_NONE_MATCH')
-        if remove_modified:
-            check_keys.append('HTTP_IF_MODIFIED_SINCE')
-        if remove_encoding:
-            check_keys.append('HTTP_ACCEPT_ENCODING')
-
-        for key in check_keys:
-            if key in self.environ:
-                del self.environ[key]
-
-    accept = converter(
-        environ_getter('HTTP_ACCEPT', rfc_section='14.1'),
-        _parse_accept, _serialize_accept, 'MIME Accept',
-        converter_args=('Accept', MIMEAccept, MIMENilAccept))
-
-    accept_charset = converter(
-        environ_getter('HTTP_ACCEPT_CHARSET', rfc_section='14.2'),
-        _parse_accept, _serialize_accept, 'accept header',
-        converter_args=('Accept-Charset', Accept, NilAccept))
-
-    accept_encoding = converter(
-        environ_getter('HTTP_ACCEPT_ENCODING', rfc_section='14.3'),
-        _parse_accept, _serialize_accept, 'accept header',
-        converter_args=('Accept-Encoding', Accept, NoAccept))
-
-    accept_language = converter(
-        environ_getter('HTTP_ACCEPT_LANGUAGE', rfc_section='14.4'),
-        _parse_accept, _serialize_accept, 'accept header',
-        converter_args=('Accept-Language', Accept, NilAccept))
-
-    ## FIXME: 14.8 Authorization
-    ## http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.8
-
-    def _cache_control__get(self):
-        """
-        Get/set/modify the Cache-Control header (section `14.9
-        <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9>`_)
-        """
-        env = self.environ
-        value = env.get('HTTP_CACHE_CONTROL', '')
-        cache_header, cache_obj = env.get('webob._cache_control', (None, None))
-        if cache_obj is not None and cache_header == value:
-            return cache_obj
-        cache_obj = CacheControl.parse(value, type='request')
-        env['webob._cache_control'] = (value, cache_obj)
-        return cache_obj
-
-    def _cache_control__set(self, value):
-        env = self.environ
-        if not value:
-            value = ""
-        if isinstance(value, dict):
-            value = CacheControl(value, type='request')
-        elif isinstance(value, CacheControl):
-            str_value = str(value)
-            env['HTTP_CACHE_CONTROL'] = str_value
-            env['webob._cache_control'] = (str_value, value)
-        else:
-            env['HTTP_CACHE_CONTROL'] = str(value)
-            if 'webob._cache_control' in env:
-                del env['webob._cache_control']
-
-    def _cache_control__del(self, value):
-        env = self.environ
-        if 'HTTP_CACHE_CONTROL' in env:
-            del env['HTTP_CACHE_CONTROL']
-        if 'webob._cache_control' in env:
-            del env['webob._cache_control']
-
-    cache_control = property(_cache_control__get, _cache_control__set, _cache_control__del, doc=_cache_control__get.__doc__)
-
-    date = converter(
-        environ_getter('HTTP_DATE', rfc_section='14.8'),
-        _parse_date, _serialize_date, 'HTTP date')
-
-    if_match = converter(
-        environ_getter('HTTP_IF_MATCH', rfc_section='14.24'),
-        _parse_etag, _serialize_etag, 'ETag', converter_args=(True,))
-
-    if_modified_since = converter(
-        environ_getter('HTTP_IF_MODIFIED_SINCE', rfc_section='14.25'),
-        _parse_date, _serialize_date, 'HTTP date')
-
-    if_none_match = converter(
-        environ_getter('HTTP_IF_NONE_MATCH', rfc_section='14.26'),
-        _parse_etag, _serialize_etag, 'ETag', converter_args=(False,))
-
-    if_range = converter(
-        environ_getter('HTTP_IF_RANGE', rfc_section='14.27'),
-        _parse_if_range, _serialize_if_range, 'IfRange object')
-
-    if_unmodified_since = converter(
-        environ_getter('HTTP_IF_UNMODIFIED_SINCE', rfc_section='14.28'),
-        _parse_date, _serialize_date, 'HTTP date')
-
-    max_forwards = converter(
-        environ_getter('HTTP_MAX_FORWARDS', rfc_section='14.31'),
-        _parse_int, _serialize_int, 'int')
-
-    pragma = environ_getter('HTTP_PRAGMA', rfc_section='14.32')
-
-    range = converter(
-        environ_getter('HTTP_RANGE', rfc_section='14.35'),
-        _parse_range, _serialize_range, 'Range object')
-
-    referer = environ_getter('HTTP_REFERER', rfc_section='14.36')
-    referrer = referer
-
-    user_agent = environ_getter('HTTP_USER_AGENT', rfc_section='14.43')
-
-    def __repr__(self):
-        msg = '<%s at %x %s %s>' % (
-            self.__class__.__name__,
-            abs(id(self)), self.method, self.url)
-        return msg
-
-    def __str__(self):
-        url = self.url
-        host = self.host_url
-        assert url.startswith(host)
-        url = url[len(host):]
-        if 'Host' not in self.headers:
-            self.headers['Host'] = self.host
-        parts = ['%s %s' % (self.method, url)]
-        for name, value in sorted(self.headers.items()):
-            parts.append('%s: %s' % (name, value))
-        parts.append('')
-        parts.append(self.body)
-        return '\r\n'.join(parts)
-
-    def call_application(self, application, catch_exc_info=False):
-        """
-        Call the given WSGI application, returning ``(status_string,
-        headerlist, app_iter)``
-
-        Be sure to call ``app_iter.close()`` if it's there.
-
-        If catch_exc_info is true, then returns ``(status_string,
-        headerlist, app_iter, exc_info)``, where the fourth item may
-        be None, but won't be if there was an exception.  If you don't
-        do this and there was an exception, the exception will be
-        raised directly.
-        """
-        captured = []
-        output = []
-        def start_response(status, headers, exc_info=None):
-            if exc_info is not None and not catch_exc_info:
-                raise exc_info[0], exc_info[1], exc_info[2]
-            captured[:] = [status, headers, exc_info]
-            return output.append
-        app_iter = application(self.environ, start_response)
-        if (not captured
-            or output):
-            try:
-                output.extend(app_iter)
-            finally:
-                if hasattr(app_iter, 'close'):
-                    app_iter.close()
-            app_iter = output
-        if catch_exc_info:
-            return (captured[0], captured[1], app_iter, captured[2])
-        else:
-            return (captured[0], captured[1], app_iter)
-
-    # Will be filled in later:
-    ResponseClass = None
-
-    def get_response(self, application, catch_exc_info=False):
-        """
-        Like ``.call_application(application)``, except returns a
-        response object with ``.status``, ``.headers``, and ``.body``
-        attributes.
-
-        This will use ``self.ResponseClass`` to figure out the class
-        of the response object to return.
-        """
-        if catch_exc_info:
-            status, headers, app_iter, exc_info = self.call_application(
-                application, catch_exc_info=True)
-            del exc_info
-        else:
-            status, headers, app_iter = self.call_application(
-                application, catch_exc_info=False)
-        return self.ResponseClass(
-            status=status, headerlist=headers, app_iter=app_iter,
-            request=self)
-
-    #@classmethod
-    def blank(cls, path, environ=None, base_url=None, headers=None, **kw):
-        """
-        Create a blank request environ (and Request wrapper) with the
-        given path (path should be urlencoded), and any keys from
-        environ.
-
-        The path will become path_info, with any query string split
-        off and used.
-
-        All necessary keys will be added to the environ, but the
-        values you pass in will take precedence.  If you pass in
-        base_url then wsgi.url_scheme, HTTP_HOST, and SCRIPT_NAME will
-        be filled in from that value.
-
-        Any extra keyword will be passed to ``__init__`` (e.g.,
-        ``decode_param_names``).
-        """
-        if _SCHEME_RE.search(path):
-            scheme, netloc, path, qs, fragment = urlparse.urlsplit(path)
-            if fragment:
-                raise TypeError(
-                    "Path cannot contain a fragment (%r)" % fragment)
-            if qs:
-                path += '?' + qs
-            if ':' not in netloc:
-                if scheme == 'http':
-                    netloc += ':80'
-                elif scheme == 'https':
-                    netloc += ':443'
-                else:
-                    raise TypeError("Unknown scheme: %r" % scheme)
-        else:
-            scheme = 'http'
-            netloc = 'localhost:80'
-        if path and '?' in path:
-            path_info, query_string = path.split('?', 1)
-            path_info = urllib.unquote(path_info)
-        else:
-            path_info = urllib.unquote(path)
-            query_string = ''
-        env = {
-            'REQUEST_METHOD': 'GET',
-            'SCRIPT_NAME': '',
-            'PATH_INFO': path_info or '',
-            'QUERY_STRING': query_string,
-            'SERVER_NAME': netloc.split(':')[0],
-            'SERVER_PORT': netloc.split(':')[1],
-            'HTTP_HOST': netloc,
-            'SERVER_PROTOCOL': 'HTTP/1.0',
-            'wsgi.version': (1, 0),
-            'wsgi.url_scheme': scheme,
-            'wsgi.input': StringIO(''),
-            'wsgi.errors': sys.stderr,
-            'wsgi.multithread': False,
-            'wsgi.multiprocess': False,
-            'wsgi.run_once': False,
-            }
-        if base_url:
-            scheme, netloc, path, query, fragment = urlparse.urlsplit(base_url)
-            if query or fragment:
-                raise ValueError(
-                    "base_url (%r) cannot have a query or fragment"
-                    % base_url)
-            if scheme:
-                env['wsgi.url_scheme'] = scheme
-            if netloc:
-                if ':' not in netloc:
-                    if scheme == 'http':
-                        netloc += ':80'
-                    elif scheme == 'https':
-                        netloc += ':443'
-                    else:
-                        raise ValueError(
-                            "Unknown scheme: %r" % scheme)
-                host, port = netloc.split(':', 1)
-                env['SERVER_PORT'] = port
-                env['SERVER_NAME'] = host
-                env['HTTP_HOST'] = netloc
-            if path:
-                env['SCRIPT_NAME'] = urllib.unquote(path)
-        if environ:
-            env.update(environ)
-        obj = cls(env, **kw)
-        if headers is not None:
-            obj.headers.update(headers)
-        return obj
-
-    blank = classmethod(blank)
-
-class Response(object):
-
-    """
-    Represents a WSGI response
-    """
-
-    default_content_type = 'text/html'
-    default_charset = 'UTF-8'
-    unicode_errors = 'strict'
-    default_conditional_response = False
-
-    def __init__(self, body=None, status='200 OK', headerlist=None, app_iter=None,
-                 request=None, content_type=None, conditional_response=NoDefault,
-                 **kw):
-        if app_iter is None:
-            if body is None:
-                body = ''
-        elif body is not None:
-            raise TypeError(
-                "You may only give one of the body and app_iter arguments")
-        self.status = status
-        if headerlist is None:
-            self._headerlist = []
-        else:
-            self._headerlist = headerlist
-        self._headers = None
-        if request is not None:
-            if hasattr(request, 'environ'):
-                self._environ = request.environ
-                self._request = request
-            else:
-                self._environ = request
-                self._request = None
-        else:
-            self._environ = self._request = None
-        if content_type is not None:
-            self.content_type = content_type
-        elif self.default_content_type is not None and headerlist is None:
-            self.content_type = self.default_content_type
-        if conditional_response is NoDefault:
-            self.conditional_response = self.default_conditional_response
-        else:
-            self.conditional_response = conditional_response
-        if 'charset' in kw:
-            # We set this early, so something like unicode_body works later
-            value = kw.pop('charset')
-            if value:
-                self.charset = value
-        elif self.default_charset and not self.charset and headerlist is None:
-            ct = self.content_type
-            if ct and (ct.startswith('text/') or ct.startswith('application/xml')
-                       or (ct.startswith('application/') and ct.endswith('+xml'))):
-                self.charset = self.default_charset
-        if app_iter is not None:
-            self._app_iter = app_iter
-            self._body = None
-        else:
-            if isinstance(body, unicode):
-                self.unicode_body = body
-            else:
-                self.body = body
-            self._app_iter = None
-        for name, value in kw.items():
-            if not hasattr(self.__class__, name):
-                # Not a basic attribute
-                raise TypeError(
-                    "Unexpected keyword: %s=%r" % (name, value))
-            setattr(self, name, value)
-
-    def __repr__(self):
-        return '<%s %x %s>' % (
-            self.__class__.__name__,
-            abs(id(self)),
-            self.status)
-
-    def __str__(self):
-        return (self.status + '\n'
-                + '\n'.join(['%s: %s' % (name, value)
-                             for name, value in self.headerlist])
-                + '\n\n'
-                + self.body)
-
-    def _status__get(self):
-        """
-        The status string
-        """
-        return self._status
-
-    def _status__set(self, value):
-        if isinstance(value, int):
-            value = str(value)
-        if not isinstance(value, str):
-            raise TypeError(
-                "You must set status to a string or integer (not %s)"
-                % type(value))
-        if ' ' not in value:
-            # Need to add a reason:
-            code = int(value)
-            reason = status_reasons[code]
-            value += ' ' + reason
-        self._status = value
-
-    status = property(_status__get, _status__set, doc=_status__get.__doc__)
-
-    def _status_int__get(self):
-        """
-        The status as an integer
-        """
-        return int(self.status.split()[0])
-    def _status_int__set(self, value):
-        self.status = value
-    status_int = property(_status_int__get, _status_int__set, doc=_status_int__get.__doc__)
-
-    def _headerlist__get(self):
-        """
-        The list of response headers
-        """
-        return self._headerlist
-
-    def _headerlist__set(self, value):
-        self._headers = None
-        if not isinstance(value, list):
-            if hasattr(value, 'items'):
-                value = value.items()
-            value = list(value)
-        self._headerlist = value
-
-    def _headerlist__del(self):
-        self.headerlist = []
-
-    headerlist = property(_headerlist__get, _headerlist__set, _headerlist__del, doc=_headerlist__get.__doc__)
-
-    def _charset__get(self):
-        """
-        Get/set the charset (in the Content-Type)
-        """
-        header = self.headers.get('content-type')
-        if not header:
-            return None
-        match = _CHARSET_RE.search(header)
-        if match:
-            return match.group(1)
-        return None
-
-    def _charset__set(self, charset):
-        if charset is None:
-            del self.charset
-            return
-        try:
-            header = self.headers.pop('content-type')
-        except KeyError:
-            raise AttributeError(
-                "You cannot set the charset when no content-type is defined")
-        match = _CHARSET_RE.search(header)
-        if match:
-            header = header[:match.start()] + header[match.end():]
-        header += '; charset=%s' % charset
-        self.headers['content-type'] = header
-
-    def _charset__del(self):
-        try:
-            header = self.headers.pop('content-type')
-        except KeyError:
-            # Don't need to remove anything
-            return
-        match = _CHARSET_RE.search(header)
-        if match:
-            header = header[:match.start()] + header[match.end():]
-        self.headers['content-type'] = header
-
-    charset = property(_charset__get, _charset__set, _charset__del, doc=_charset__get.__doc__)
-
-    def _content_type__get(self):
-        """
-        Get/set the Content-Type header (or None), *without* the
-        charset or any parameters.
-
-        If you include parameters (or ``;`` at all) when setting the
-        content_type, any existing parameters will be deleted;
-        otherwise they will be preserved.
-        """
-        header = self.headers.get('content-type')
-        if not header:
-            return None
-        return header.split(';', 1)[0]
-
-    def _content_type__set(self, value):
-        if ';' not in value:
-            header = self.headers.get('content-type', '')
-            if ';' in header:
-                params = header.split(';', 1)[1]
-                value += ';' + params
-        self.headers['content-type'] = value
-
-    def _content_type__del(self):
-        try:
-            del self.headers['content-type']
-        except KeyError:
-            pass
-
-    content_type = property(_content_type__get, _content_type__set,
-                            _content_type__del, doc=_content_type__get.__doc__)
-
-    def _content_type_params__get(self):
-        """
-        Returns a dictionary of all the parameters in the content type.
-        """
-        params = self.headers.get('content-type', '')
-        if ';' not in params:
-            return {}
-        params = params.split(';', 1)[1]
-        result = {}
-        for match in _PARAM_RE.finditer(params):
-            result[match.group(1)] = match.group(2) or match.group(3) or ''
-        return result
-
-    def _content_type_params__set(self, value_dict):
-        if not value_dict:
-            del self.content_type_params
-            return
-        params = []
-        for k, v in sorted(value_dict.items()):
-            if not _OK_PARAM_RE.search(v):
-                ## FIXME: I'm not sure what to do with "'s in the parameter value
-                ## I think it might be simply illegal
-                v = '"%s"' % v.replace('"', '\\"')
-            params.append('; %s=%s' % (k, v))
-        ct = self.headers.pop('content-type', '').split(';', 1)[0]
-        ct += ''.join(params)
-        self.headers['content-type'] = ct
-
-    def _content_type_params__del(self, value):
-        self.headers['content-type'] = self.headers.get('content-type', '').split(';', 1)[0]
-
-    content_type_params = property(_content_type_params__get, _content_type_params__set, _content_type_params__del, doc=_content_type_params__get.__doc__)
-
-    def _headers__get(self):
-        """
-        The headers in a dictionary-like object
-        """
-        if self._headers is None:
-            self._headers = HeaderDict.view_list(self.headerlist)
-        return self._headers
-
-    def _headers__set(self, value):
-        if hasattr(value, 'items'):
-            value = value.items()
-        self.headerlist = value
-        self._headers = None
-
-    headers = property(_headers__get, _headers__set, doc=_headers__get.__doc__)
-
-    def _body__get(self):
-        """
-        The body of the response, as a ``str``.  This will read in the
-        entire app_iter if necessary.
-        """
-        if self._body is None:
-            if self._app_iter is None:
-                raise AttributeError(
-                    "No body has been set")
-            try:
-                self._body = ''.join(self._app_iter)
-            finally:
-                if hasattr(self._app_iter, 'close'):
-                    self._app_iter.close()
-            self._app_iter = None
-            self.content_length = len(self._body)
-        return self._body
-
-    def _body__set(self, value):
-        if isinstance(value, unicode):
-            raise TypeError(
-                "You cannot set Response.body to a unicode object (use Response.unicode_body)")
-        if not isinstance(value, str):
-            raise TypeError(
-                "You can only set the body to a str (not %s)"
-                % type(value))
-        try:
-            if self._body or self._app_iter:
-                self.content_md5 = None
-        except AttributeError:
-            # if setting body early in initialization _body and _app_iter don't exist yet
-            pass
-        self._body = value
-        self.content_length = len(value)
-        self._app_iter = None
-
-    def _body__del(self):
-        self._body = None
-        self.content_length = None
-        self._app_iter = None
-
-    body = property(_body__get, _body__set, _body__del, doc=_body__get.__doc__)
-
-    def _body_file__get(self):
-        """
-        Returns a file-like object that can be used to write to the
-        body.  If you passed in a list app_iter, that app_iter will be
-        modified by writes.
-        """
-        return ResponseBodyFile(self)
-
-    def _body_file__del(self):
-        del self.body
-
-    body_file = property(_body_file__get, fdel=_body_file__del, doc=_body_file__get.__doc__)
-
-    def write(self, text):
-        if isinstance(text, unicode):
-            self.unicode_body += text
-        else:
-            self.body += text
-
-    def _unicode_body__get(self):
-        """
-        Get/set the unicode value of the body (using the charset of the Content-Type)
-        """
-        if not self.charset:
-            raise AttributeError(
-                "You cannot access Response.unicode_body unless charset is set")
-        body = self.body
-        return body.decode(self.charset, self.unicode_errors)
-
-    def _unicode_body__set(self, value):
-        if not self.charset:
-            raise AttributeError(
-                "You cannot access Response.unicode_body unless charset is set")
-        if not isinstance(value, unicode):
-            raise TypeError(
-                "You can only set Response.unicode_body to a unicode string (not %s)" % type(value))
-        self.body = value.encode(self.charset)
-
-    def _unicode_body__del(self):
-        del self.body
-
-    unicode_body = property(_unicode_body__get, _unicode_body__set, _unicode_body__del, doc=_unicode_body__get.__doc__)
-
-    def _app_iter__get(self):
-        """
-        Returns the app_iter of the response.
-
-        If body was set, this will create an app_iter from that body
-        (a single-item list)
-        """
-        if self._app_iter is None:
-            if self._body is None:
-                raise AttributeError(
-                    "No body or app_iter has been set")
-            return [self._body]
-        else:
-            return self._app_iter
-
-    def _app_iter__set(self, value):
-        if self._body is not None:
-            # Undo the automatically-set content-length
-            self.content_length = None
-        self._app_iter = value
-        self._body = None
-
-    def _app_iter__del(self):
-        self.content_length = None
-        self._app_iter = self._body = None
-
-    app_iter = property(_app_iter__get, _app_iter__set, _app_iter__del, doc=_app_iter__get.__doc__)
-
-    def set_cookie(self, key, value='', max_age=None,
-                   path='/', domain=None, secure=None, httponly=False,
-                   version=None, comment=None, expires=None):
-        """
-        Set (add) a cookie for the response
-        """
-        if isinstance(value, unicode) and self.charset is not None:
-            value = '"%s"' % value.encode(self.charset)
-        cookies = BaseCookie()
-        cookies[key] = value
-        if isinstance(max_age, timedelta):
-            max_age = max_age.seconds + max_age.days*24*60*60
-        if max_age is not None and expires is None:
-            expires = datetime.utcnow() + timedelta(seconds=max_age)
-        if isinstance(expires, timedelta):
-            expires = datetime.utcnow() + expires
-        if isinstance(expires, datetime):
-            expires = '"'+_serialize_cookie_date(expires)+'"'
-        for var_name, var_value in [
-            ('max_age', max_age),
-            ('path', path),
-            ('domain', domain),
-            ('secure', secure),
-            ('HttpOnly', httponly),
-            ('version', version),
-            ('comment', comment),
-            ('expires', expires),
-            ]:
-            if var_value is not None and var_value is not False:
-                cookies[key][var_name.replace('_', '-')] = str(var_value)
-        header_value = cookies[key].output(header='').lstrip()
-        if header_value.endswith(';'):
-            # Python 2.4 adds a trailing ; to the end, strip it to be
-            # consistent with 2.5
-            header_value = header_value[:-1]
-        self.headerlist.append(('Set-Cookie', header_value))
-
-    def delete_cookie(self, key, path='/', domain=None):
-        """
-        Delete a cookie from the client.  Note that path and domain must match
-        how the cookie was originally set.
-
-        This sets the cookie to the empty string, and max_age=0 so
-        that it should expire immediately.
-        """
-        self.set_cookie(key, '', path=path, domain=domain,
-                        max_age=0, expires=timedelta(days=-5))
-
-    def unset_cookie(self, key):
-        """
-        Unset a cookie with the given name (remove it from the
-        response).  If there are multiple cookies (e.g., two cookies
-        with the same name and different paths or domains), all such
-        cookies will be deleted.
-        """
-        existing = self.headers.getall('Set-Cookie')
-        if not existing:
-            raise KeyError(
-                "No cookies at all have been set")
-        del self.headers['Set-Cookie']
-        found = False
-        for header in existing:
-            cookies = BaseCookie()
-            cookies.load(header)
-            if key in cookies:
-                found = True
-                del cookies[key]
-                header = cookies.output(header='').lstrip()
-            if header:
-                if header.endswith(';'):
-                    # Python 2.4 adds a trailing ; to the end, strip it
-                    # to be consistent with 2.5
-                    header = header[:-1]
-                self.headers.add('Set-Cookie', header)
-        if not found:
-            raise KeyError(
-                "No cookie has been set with the name %r" % key)
-
-    def _location__get(self):
-        """
-        Retrieve the Location header of the response, or None if there
-        is no header.  If the header is not absolute and this response
-        is associated with a request, make the header absolute.
-
-        For more information see `section 14.30
-        <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.30>`_.
-        """
-        if 'location' not in self.headers:
-            return None
-        location = self.headers['location']
-        if _SCHEME_RE.search(location):
-            # Absolute
-            return location
-        if self.request is not None:
-            base_uri = self.request.url
-            location = urlparse.urljoin(base_uri, location)
-        return location
-
-    def _location__set(self, value):
-        if not _SCHEME_RE.search(value):
-            # Not absolute, see if we can make it absolute
-            if self.request is not None:
-                value = urlparse.urljoin(self.request.url, value)
-        self.headers['location'] = value
-
-    def _location__del(self):
-        if 'location' in self.headers:
-            del self.headers['location']
-
-    location = property(_location__get, _location__set, _location__del, doc=_location__get.__doc__)
-
-    accept_ranges = header_getter('Accept-Ranges', rfc_section='14.5')
-
-    age = converter(
-        header_getter('Age', rfc_section='14.6'),
-        _parse_int_safe, _serialize_int, 'int')
-
-    allow = converter(
-        header_getter('Allow', rfc_section='14.7'),
-        _parse_list, _serialize_list, 'list')
-
-    _cache_control_obj = None
-
-    def _cache_control__get(self):
-        """
-        Get/set/modify the Cache-Control header (section `14.9
-        <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9>`_)
-        """
-        value = self.headers.get('cache-control', '')
-        if self._cache_control_obj is None:
-            self._cache_control_obj = CacheControl.parse(value, updates_to=self._update_cache_control, type='response')
-            self._cache_control_obj.header_value = value
-        if self._cache_control_obj.header_value != value:
-            new_obj = CacheControl.parse(value, type='response')
-            self._cache_control_obj.properties.clear()
-            self._cache_control_obj.properties.update(new_obj.properties)
-            self._cache_control_obj.header_value = value
-        return self._cache_control_obj
-
-    def _cache_control__set(self, value):
-        # This actually becomes a copy
-        if not value:
-            value = ""
-        if isinstance(value, dict):
-            value = CacheControl(value, 'response')
-        if isinstance(value, unicode):
-            value = str(value)
-        if isinstance(value, str):
-            if self._cache_control_obj is None:
-                self.headers['Cache-Control'] = value
-                return
-            value = CacheControl.parse(value, 'response')
-        cache = self.cache_control
-        cache.properties.clear()
-        cache.properties.update(value.properties)
-
-    def _cache_control__del(self):
-        self.cache_control = {}
-
-    def _update_cache_control(self, prop_dict):
-        value = serialize_cache_control(prop_dict)
-        if not value:
-            if 'Cache-Control' in self.headers:
-                del self.headers['Cache-Control']
-        else:
-            self.headers['Cache-Control'] = value
-
-    cache_control = property(_cache_control__get, _cache_control__set, _cache_control__del, doc=_cache_control__get.__doc__)
-
-    def cache_expires(self, seconds=0, **kw):
-        """
-        Set expiration on this request.  This sets the response to
-        expire in the given seconds, and any other attributes are used
-        for cache_control (e.g., private=True, etc).
-        """
-        cache_control = self.cache_control
-        if isinstance(seconds, timedelta):
-            seconds = timedelta_to_seconds(seconds)
-        if not seconds:
-            # To really expire something, you have to force a
-            # bunch of these cache control attributes, and IE may
-            # not pay attention to those still so we also set
-            # Expires.
-            cache_control.no_store = True
-            cache_control.no_cache = True
-            cache_control.must_revalidate = True
-            cache_control.max_age = 0
-            cache_control.post_check = 0
-            cache_control.pre_check = 0
-            self.expires = datetime.utcnow()
-            if 'last-modified' not in self.headers:
-                self.last_modified = datetime.utcnow()
-            self.pragma = 'no-cache'
-        else:
-            cache_control.max_age = seconds
-            self.expires = datetime.utcnow() + timedelta(seconds=seconds)
-        for name, value in kw.items():
-            setattr(cache_control, name, value)
-
-    content_encoding = header_getter('Content-Encoding', rfc_section='14.11')
-
-    def encode_content(self, encoding='gzip'):
-        """
-        Encode the content with the given encoding (only gzip and
-        identity are supported).
-        """
-        if encoding == 'identity':
-            self.decode_content()
-            return
-        if encoding != 'gzip':
-            raise ValueError(
-                "Unknown encoding: %r" % encoding)
-        if self.content_encoding:
-            if self.content_encoding == encoding:
-                return
-            self.decode_content()
-        from webob.util.safegzip import GzipFile
-        f = StringIO()
-        gzip_f = GzipFile(filename='', mode='w', fileobj=f)
-        gzip_f.write(self.body)
-        gzip_f.close()
-        new_body = f.getvalue()
-        f.close()
-        self.content_encoding = 'gzip'
-        self.body = new_body
-
-    def decode_content(self):
-        content_encoding = self.content_encoding
-        if not content_encoding or content_encoding == 'identity':
-            return
-        if content_encoding != 'gzip':
-            raise ValueError(
-                "I don't know how to decode the content %s" % content_encoding)
-        from webob.util.safegzip import GzipFile
-        f = StringIO(self.body)
-        gzip_f = GzipFile(filename='', mode='r', fileobj=f)
-        new_body = gzip_f.read()
-        gzip_f.close()
-        f.close()
-        self.content_encoding = None
-        self.body = new_body
-
-    content_language = converter(
-        header_getter('Content-Language', rfc_section='14.12'),
-        _parse_list, _serialize_list, 'list')
-
-    content_location = header_getter(
-        'Content-Location', rfc_section='14.14')
-
-    content_md5 = header_getter(
-        'Content-MD5', rfc_section='14.14')
-
-    content_range = converter(
-        header_getter('Content-Range', rfc_section='14.16'),
-        _parse_content_range, _serialize_content_range, 'ContentRange object')
-
-    content_length = converter(
-        header_getter('Content-Length', rfc_section='14.17'),
-        _parse_int, _serialize_int, 'int')
-
-    date = converter(
-        header_getter('Date', rfc_section='14.18'),
-        _parse_date, _serialize_date, 'HTTP date')
-
-    etag = header_getter('ETag', rfc_section='14.19')
-
-    def md5_etag(self, body=None, set_content_md5=False, set_conditional_response=False):
-        """
-        Generate an etag for the response object using an MD5 hash of
-        the body (the body parameter, or ``self.body`` if not given)
-
-        Sets ``self.etag``
-        If ``set_content_md5`` is True sets ``self.content_md5`` as well
-        If ``set_conditional_response`` is True sets ``self.conditional_response`` to True
-        """
-        if body is None:
-            body = self.body
-        try:
-            from hashlib import md5
-        except ImportError:
-            from md5 import md5
-        h = md5(body)
-        md5_digest = h.digest().encode('base64').replace('\n', '').strip('=')
-        self.etag = md5_digest
-        if set_content_md5:
-            self.content_md5 = md5_digest
-        if set_conditional_response:
-            self.conditional_response = True
-
-    expires = converter(
-        header_getter('Expires', rfc_section='14.21'),
-        _parse_date, _serialize_date, 'HTTP date')
-
-    last_modified = converter(
-        header_getter('Last-Modified', rfc_section='14.29'),
-        _parse_date, _serialize_date, 'HTTP date')
-
-    pragma = header_getter('Pragma', rfc_section='14.32')
-
-    retry_after = converter(
-        header_getter('Retry-After', rfc_section='14.37'),
-        _parse_date_delta, _serialize_date_delta, 'HTTP date or delta seconds')
-
-    server = header_getter('Server', rfc_section='14.38')
-
-    ## FIXME: I realize response.vary += 'something' won't work.  It should.
-    ## Maybe for all listy headers.
-    vary = converter(
-        header_getter('Vary', rfc_section='14.44'),
-        _parse_list, _serialize_list, 'list')
-
-    ## FIXME: 14.47 WWW-Authenticate
-    ## http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.47
-
-
-    def _request__get(self):
-        """
-        Return the request associated with this response if any.
-        """
-        if self._request is None and self._environ is not None:
-            self._request = self.RequestClass(self._environ)
-        return self._request
-
-    def _request__set(self, value):
-        if value is None:
-            del self.request
-            return
-        if isinstance(value, dict):
-            self._environ = value
-            self._request = None
-        else:
-            self._request = value
-            self._environ = value.environ
-
-    def _request__del(self):
-        self._request = self._environ = None
-
-    request = property(_request__get, _request__set, _request__del, doc=_request__get.__doc__)
-
-    def _environ__get(self):
-        """
-        Get/set the request environ associated with this response, if
-        any.
-        """
-        return self._environ
-
-    def _environ__set(self, value):
-        if value is None:
-            del self.environ
-        self._environ = value
-        self._request = None
-
-    def _environ__del(self):
-        self._request = self._environ = None
-
-    environ = property(_environ__get, _environ__set, _environ__del, doc=_environ__get.__doc__)
-
-    def __call__(self, environ, start_response):
-        """
-        WSGI application interface
-        """
-        if self.conditional_response:
-            return self.conditional_response_app(environ, start_response)
-        start_response(self.status, self.headerlist)
-        if environ['REQUEST_METHOD'] == 'HEAD':
-            # Special case here...
-            return []
-        return self.app_iter
-
-    _safe_methods = ('GET', 'HEAD')
-
-    def conditional_response_app(self, environ, start_response):
-        """
-        Like the normal __call__ interface, but checks conditional headers:
-
-        * If-Modified-Since   (304 Not Modified; only on GET, HEAD)
-        * If-None-Match       (304 Not Modified; only on GET, HEAD)
-        * Range               (406 Partial Content; only on GET, HEAD)
-        """
-        req = self.RequestClass(environ)
-        status304 = False
-        if req.method in self._safe_methods:
-            if req.if_modified_since and self.last_modified and self.last_modified <= req.if_modified_since:
-                status304 = True
-            if req.if_none_match and self.etag:
-                ## FIXME: should a weak match be okay?
-                if self.etag in req.if_none_match:
-                    status304 = True
-                else:
-                    # Even if If-Modified-Since matched, if ETag doesn't then reject it
-                    status304 = False
-        if status304:
-            start_response('304 Not Modified', self.headerlist)
-            return []
-        if req.method == 'HEAD':
-            start_response(self.status, self.headerlist)
-            return []
-        if (req.range and req.if_range.match_response(self)
-            and self.content_range is None
-            and req.method == 'GET'
-            and self.status_int == 200):
-            content_range = req.range.content_range(self.content_length)
-            if content_range is not None:
-                app_iter = self.app_iter_range(content_range.start, content_range.stop)
-                if app_iter is not None:
-                    headers = list(self.headerlist)
-                    headers.append(('Content-Range', str(content_range)))
-                    start_response('206 Partial Content', headers)
-                    return app_iter
-        start_response(self.status, self.headerlist)
-        return self.app_iter
-
-    def app_iter_range(self, start, stop):
-        """
-        Return a new app_iter built from the response app_iter, that
-        serves up only the given ``start:stop`` range.
-        """
-        if self._app_iter is None:
-            return [self.body[start:stop]]
-        app_iter = self.app_iter
-        if hasattr(app_iter, 'app_iter_range'):
-            return app_iter.app_iter_range(start, stop)
-        return AppIterRange(app_iter, start, stop)
-
-
-Request.ResponseClass = Response
-Response.RequestClass = Request
-
-def _cgi_FieldStorage__repr__patch(self):
-    """ monkey patch for FieldStorage.__repr__
-
-    Unbelievely, the default __repr__ on FieldStorage reads
-    the entire file content instead of being sane about it.
-    This is a simple replacement that doesn't do that
-    """
-    if self.file:
-        return "FieldStorage(%r, %r)" % (
-                self.name, self.filename)
-    return "FieldStorage(%r, %r, %r)" % (
-             self.name, self.filename, self.value)
-
-cgi.FieldStorage.__repr__ = _cgi_FieldStorage__repr__patch
-
-class FakeCGIBody(object):
-
-    def __init__(self, vars):
-        self.vars = vars
-        self._body = None
-        self.position = 0
-
-    def read(self, size=-1):
-        body = self._get_body()
-        if size == -1:
-            v = body[self.position:]
-            self.position = len(body)
-            return v
-        else:
-            v = body[self.position:self.position+size]
-            self.position = min(len(body), self.position+size)
-            return v
-
-    def _get_body(self):
-        if self._body is None:
-            self._body = urllib.urlencode(self.vars.items())
-        return self._body
-
-    def readline(self, size=None):
-        # We ignore size, but allow it to be hinted
-        rest = self._get_body()[self.position:]
-        next = rest.find('\r\n')
-        if next == -1:
-            return self.read()
-        self.position += next+2
-        return rest[:next+2]
-
-    def readlines(self, hint=None):
-        # Again, allow hint but ignore
-        body = self._get_body()
-        rest = body[self.position:]
-        self.position = len(body)
-        result = []
-        while 1:
-            next = rest.find('\r\n')
-            if next == -1:
-                result.append(rest)
-                break
-            result.append(rest[:next+2])
-            rest = rest[next+2:]
-        return result
-
-    def __iter__(self):
-        return iter(self.readlines())
-
-    def __repr__(self):
-        inner = repr(self.vars)
-        if len(inner) > 20:
-            inner = inner[:15] + '...' + inner[-5:]
-        return '<%s at %x viewing %s>' % (
-            self.__class__.__name__,
-            abs(id(self)), inner)
-
-    #@classmethod
-    def update_environ(cls, environ, vars):
-        obj = cls(vars)
-        environ['CONTENT_LENGTH'] = '-1'
-        environ['wsgi.input'] = obj
-
-    update_environ = classmethod(update_environ)
-
-class ResponseBodyFile(object):
-
-    def __init__(self, response):
-        self.response = response
-
-    def __repr__(self):
-        return '<body_file for %r>' % (
-            self.response)
-
-    def close(self):
-        raise NotImplementedError(
-            "Response bodies cannot be closed")
-
-    def flush(self):
-        pass
-
-    def write(self, s):
-        if isinstance(s, unicode):
-            if self.response.charset is not None:
-                s = s.encode(self.response.charset)
-            else:
-                raise TypeError(
-                    "You can only write unicode to Response.body_file "
-                    "if charset has been set")
-        if not isinstance(s, str):
-            raise TypeError(
-                "You can only write str to a Response.body_file, not %s"
-                % type(s))
-        if not isinstance(self.response._app_iter, list):
-            body = self.response.body
-            if body:
-                self.response.app_iter = [body]
-            else:
-                self.response.app_iter = []
-        self.response.app_iter.append(s)
-
-    def writelines(self, seq):
-        for item in seq:
-            self.write(item)
-
-    closed = False
-
-    def encoding(self):
-        """
-        The encoding of the file (inherited from response.charset)
-        """
-        return self.response.charset
-
-    encoding = property(encoding, doc=encoding.__doc__)
-
-    mode = 'wb'
-
-class AppIterRange(object):
-    """
-    Wraps an app_iter, returning just a range of bytes
-    """
-
-    def __init__(self, app_iter, start, stop):
-        assert start >= 0, "Bad start: %r" % start
-        assert stop is None or (stop >= 0 and stop >= start), (
-            "Bad stop: %r" % stop)
-        self.app_iter = app_iter
-        self.app_iterator = iter(app_iter)
-        self.start = start
-        if stop is None:
-            self.length = -1
-        else:
-            self.length = stop - start
-        if start:
-            self._served = None
-        else:
-            self._served = 0
-        if hasattr(app_iter, 'close'):
-            self.close = app_iter.close
-
-    def __iter__(self):
-        return self
-
-    def next(self):
-        if self._served is None:
-            # Haven't served anything; need to skip some leading bytes
-            skipped = 0
-            start = self.start
-            while 1:
-                chunk = self.app_iterator.next()
-                skipped += len(chunk)
-                extra = skipped - start
-                if extra == 0:
-                    self._served = 0
-                    break
-                elif extra > 0:
-                    self._served = extra
-                    return chunk[-extra:]
-        length = self.length
-        if length is None:
-            # Spent
-            raise StopIteration
-        chunk = self.app_iterator.next()
-        if length == -1:
-            return chunk
-        if self._served + len(chunk) > length:
-            extra = self._served + len(chunk) - length
-            self.length = None
-            return chunk[:-extra]
-        self._served += len(chunk)
-        return chunk
-
diff --git a/lib/webob/acceptparse.py b/lib/webob/acceptparse.py
@@ -1,297 +0,0 @@
-"""
-Parses a variety of ``Accept-*`` headers.
-
-These headers generally take the form of::
-
-    value1; q=0.5, value2; q=0
-
-Where the ``q`` parameter is optional.  In theory other parameters
-exists, but this ignores them.
-"""
-
-import re
-try:
-    sorted
-except NameError:
-    from webob.compat import sorted
-
-part_re = re.compile(
-    r',\s*([^\s;,\n]+)(?:[^,]*?;\s*q=([0-9.]*))?')
-
-def parse_accept(value):
-    """
-    Parses an ``Accept-*`` style header.
-
-    A list of ``[(value, quality), ...]`` is returned.  ``quality``
-    will be 1 if it was not given.
-    """
-    result = []
-    for match in part_re.finditer(','+value):
-        name = match.group(1)
-        if name == 'q':
-            continue
-        quality = match.group(2) or ''
-        if not quality:
-            quality = 1
-        else:
-            try:
-                quality = max(min(float(quality), 1), 0)
-            except ValueError:
-                quality = 1
-        result.append((name, quality))
-    return result
-
-class Accept(object):
-    """
-    Represents a generic ``Accept-*`` style header.
-
-    This object should not be modified.  To add items you can use
-    ``accept_obj + 'accept_thing'`` to get a new object
-    """
-
-    def __init__(self, header_name, header_value):
-        self.header_name = header_name
-        self.header_value = header_value
-        self._parsed = parse_accept(header_value)
-
-    def __repr__(self):
-        return '<%s at %x %s: %s>' % (
-            self.__class__.__name__,
-            abs(id(self)),
-            self.header_name, str(self))
-
-    def __str__(self):
-        result = []
-        for match, quality in self._parsed:
-            if quality != 1:
-                match = '%s;q=%0.1f' % (match, quality)
-            result.append(match)
-        return ', '.join(result)
-
-    # FIXME: should subtraction be allowed?
-    def __add__(self, other, reversed=False):
-        if isinstance(other, Accept):
-            other = other.header_value
-        if hasattr(other, 'items'):
-            other = sorted(other.items(), key=lambda item: -item[1])
-        if isinstance(other, (list, tuple)):
-            result = []
-            for item in other:
-                if isinstance(item, (list, tuple)):
-                    name, quality = item
-                    result.append('%s; q=%s' % (name, quality))
-                else:
-                    result.append(item)
-            other = ', '.join(result)
-        other = str(other)
-        my_value = self.header_value
-        if reversed:
-            other, my_value = my_value, other
-        if not other:
-            new_value = my_value
-        elif not my_value:
-            new_value = other
-        else:
-            new_value = my_value + ', ' + other
-        return self.__class__(self.header_name, new_value)
-
-    def __radd__(self, other):
-        return self.__add__(other, True)
-
-    def __contains__(self, match):
-        """
-        Returns true if the given object is listed in the accepted
-        types.
-        """
-        for item, quality in self._parsed:
-            if self._match(item, match):
-                return True
-
-    def quality(self, match):
-        """
-        Return the quality of the given match.  Returns None if there
-        is no match (not 0).
-        """
-        for item, quality in self._parsed:
-            if self._match(item, match):
-                return quality
-        return None
-    
-    def first_match(self, matches):
-        """
-        Returns the first match in the sequences of matches that is
-        allowed.  Ignores quality.  Returns the first item if nothing
-        else matches; or if you include None at the end of the match
-        list then that will be returned.
-        """
-        if not matches:
-            raise ValueError(
-                "You must pass in a non-empty list")
-        for match in matches:
-            for item, quality in self._parsed:
-                if self._match(item, match):
-                    return match
-            if match is None:
-                return None
-        return matches[0]
-    
-    def best_match(self, matches, default_match=None):
-        """
-        Returns the best match in the sequence of matches.
-
-        The sequence can be a simple sequence, or you can have
-        ``(match, server_quality)`` items in the sequence.  If you
-        have these tuples then the client quality is multiplied by the
-        server_quality to get a total.
-
-        default_match (default None) is returned if there is no intersection.
-        """
-        best_quality = -1
-        best_match = default_match
-        for match_item in matches:
-            if isinstance(match_item, (tuple, list)):
-                match, server_quality = match_item
-            else:
-                match = match_item
-                server_quality = 1
-            for item, quality in self._parsed:
-                possible_quality = server_quality * quality
-                if possible_quality < best_quality:
-                    continue
-                if self._match(item, match):
-                    best_quality = possible_quality
-                    best_match = match
-        return best_match
-
-    def best_matches(self, fallback=None):
-        """
-        Return all the matches in order of quality, with fallback (if
-        given) at the end.
-        """
-        items = [
-            i for i, q in sorted(self._parsed, key=lambda iq: -iq[1])]
-        if fallback:
-            for index, item in enumerate(items):
-                if self._match(item, fallback):
-                    items[index+1:] = []
-                    break
-            else:
-                items.append(fallback)
-        return items
-
-    def _match(self, item, match):
-        return item.lower() == match.lower() or item == '*'
-
-class NilAccept(object):
-
-    """
-    Represents an Accept header with no value.
-    """
-
-    MasterClass = Accept
-
-    def __init__(self, header_name):
-        self.header_name = header_name
-
-    def __repr__(self):
-        return '<%s for %s: %s>' % (
-            self.__class__.__name__, self.header_name, self.MasterClass)
-
-    def __str__(self):
-        return ''
-
-    def __add__(self, item):
-        if isinstance(item, self.MasterClass):
-            return item
-        else:
-            return self.MasterClass(self.header_name, '') + item
-
-    def __radd__(self, item):
-        if isinstance(item, self.MasterClass):
-            return item
-        else:
-            return item + self.MasterClass(self.header_name, '')
-
-    def __contains__(self, item):
-        return True
-
-    def quality(self, match, default_quality=1):
-        return 0
-
-    def first_match(self, matches):
-        return matches[0]
-
-    def best_match(self, matches, default_match=None):
-        best_quality = -1
-        best_match = default_match
-        for match_item in matches:
-            if isinstance(match_item, (list, tuple)):
-                match, quality = match_item
-            else:
-                match = match_item
-                quality = 1
-            if quality > best_quality:
-                best_match = match
-                best_quality = quality
-        return best_match
-
-    def best_matches(self, fallback=None):
-        if fallback:
-            return [fallback]
-        else:
-            return []
-
-class NoAccept(NilAccept):
-
-    def __contains__(self, item):
-        return False
-
-class MIMEAccept(Accept):
-
-    """
-    Represents the ``Accept`` header, which is a list of mimetypes.
-
-    This class knows about mime wildcards, like ``image/*``
-    """
-
-    def _match(self, item, match):
-        item = item.lower()
-        if item == '*':
-            item = '*/*'
-        match = match.lower()
-        if match == '*':
-            match = '*/*'
-        if '/' not in item:
-            # Bad, but we ignore
-            return False
-        if '/' not in match:
-            raise ValueError(
-                "MIME matches must include / (bad: %r)" % match)
-        item_major, item_minor = item.split('/', 1)
-        match_major, match_minor = match.split('/', 1)
-        if match_major == '*' and match_minor != '*':
-            raise ValueError(
-                "A MIME type of %r doesn't make sense" % match)
-        if item_major == '*' and item_minor != '*':
-            # Bad, but we ignore
-            return False
-        if ((item_major == '*' and item_minor == '*')
-            or (match_major == '*' and match_minor == '*')):
-            return True
-        if (item_major == match_major
-            and ((item_minor == '*' or match_minor == '*')
-                 or item_minor == match_minor)):
-            return True
-        return False
-
-    def accept_html(self):
-        """
-        Returns true if any HTML-like type is accepted
-        """
-        return ('text/html' in self
-                or 'application/xhtml+xml' in self
-                or 'application/xml' in self
-                or 'text/xml' in self)
-
-class MIMENilAccept(NilAccept):
-    MasterClass = MIMEAccept
diff --git a/lib/webob/byterange.py b/lib/webob/byterange.py
@@ -1,295 +0,0 @@
-class Range(object):
-
-    """
-    Represents the Range header.
-
-    This only represents ``bytes`` ranges, which are the only kind
-    specified in HTTP.  This can represent multiple sets of ranges,
-    but no place else is this multi-range facility supported.
-    """
-
-    def __init__(self, ranges):
-        for begin, end in ranges:
-            assert end is None or end >= 0, "Bad ranges: %r" % ranges
-        self.ranges = ranges
-
-    def satisfiable(self, length):
-        """
-        Returns true if this range can be satisfied by the resource
-        with the given byte length.
-        """
-        for begin, end in self.ranges:
-            if end is not None and end >= length:
-                return False
-        return True
-
-    def range_for_length(self, length):
-        """
-        *If* there is only one range, and *if* it is satisfiable by
-        the given length, then return a (begin, end) non-inclusive range
-        of bytes to serve.  Otherwise return None
-
-        If length is None (unknown length), then the resulting range
-        may be (begin, None), meaning it should be served from that
-        point.  If it's a range with a fixed endpoint we won't know if
-        it is satisfiable, so this will return None.
-        """
-        if len(self.ranges) != 1:
-            return None
-        begin, end = self.ranges[0]
-        if length is None:
-            # Unknown; only works with ranges with no end-point
-            if end is None:
-                return (begin, end)
-            return None
-        if end >= length:
-            # Overshoots the end
-            return None
-        return (begin, end)
-
-    def content_range(self, length):
-        """
-        Works like range_for_length; returns None or a ContentRange object
-
-        You can use it like::
-
-            response.content_range = req.range.content_range(response.content_length)
-
-        Though it's still up to you to actually serve that content range!
-        """
-        range = self.range_for_length(length)
-        if range is None:
-            return None
-        return ContentRange(range[0], range[1], length)
-
-    def __str__(self):
-        return self.serialize_bytes('bytes', self.python_ranges_to_bytes(self.ranges))
-
-    def __repr__(self):
-        return '<%s ranges=%s>' % (
-            self.__class__.__name__,
-            ', '.join(map(repr, self.ranges)))
-
-    #@classmethod
-    def parse(cls, header):
-        """
-        Parse the header; may return None if header is invalid
-        """
-        bytes = cls.parse_bytes(header)
-        if bytes is None:
-            return None
-        units, ranges = bytes
-        if units.lower() != 'bytes':
-            return None
-        ranges = cls.bytes_to_python_ranges(ranges)
-        if ranges is None:
-            return None
-        return cls(ranges)
-    parse = classmethod(parse)
-
-    #@staticmethod
-    def parse_bytes(header):
-        """
-        Parse a Range header into (bytes, list_of_ranges).  Note that the
-        ranges are *inclusive* (like in HTTP, not like in Python
-        typically).
-
-        Will return None if the header is invalid
-        """
-        if not header:
-            raise TypeError(
-                "The header must not be empty")
-        ranges = []
-        last_end = 0
-        try:
-            (units, range) = header.split("=", 1)
-            units = units.strip().lower()
-            for item in range.split(","):
-                if '-' not in item:
-                    raise ValueError()
-                if item.startswith('-'):
-                    # This is a range asking for a trailing chunk
-                    if last_end < 0:
-                        raise ValueError('too many end ranges')
-                    begin = int(item)
-                    end = None
-                    last_end = -1
-                else:
-                    (begin, end) = item.split("-", 1)
-                    begin = int(begin)
-                    if begin < last_end or last_end < 0:
-                        print begin, last_end
-                        raise ValueError('begin<last_end, or last_end<0')
-                    if not end.strip():
-                        end = None
-                    else:
-                        end = int(end)
-                    if end is not None and begin > end:
-                        raise ValueError('begin>end')
-                    last_end = end
-                ranges.append((begin, end))
-        except ValueError, e:
-            # In this case where the Range header is malformed,
-            # section 14.16 says to treat the request as if the
-            # Range header was not present.  How do I log this?
-            print e
-            return None
-        return (units, ranges)
-    parse_bytes = staticmethod(parse_bytes)
-
-    #@staticmethod
-    def serialize_bytes(units, ranges):
-        """
-        Takes the output of parse_bytes and turns it into a header
-        """
-        parts = []
-        for begin, end in ranges:
-            if end is None:
-                if begin >= 0:
-                    parts.append('%s-' % begin)
-                else:
-                    parts.append(str(begin))
-            else:
-                if begin < 0:
-                    raise ValueError(
-                        "(%r, %r) should have a non-negative first value" % (begin, end))
-                if end < 0:
-                    raise ValueError(
-                        "(%r, %r) should have a non-negative second value" % (begin, end))
-                parts.append('%s-%s' % (begin, end))
-        return '%s=%s' % (units, ','.join(parts))
-    serialize_bytes = staticmethod(serialize_bytes)
-
-    #@staticmethod
-    def bytes_to_python_ranges(ranges, length=None):
-        """
-        Converts the list-of-ranges from parse_bytes() to a Python-style
-        list of ranges (non-inclusive end points)
-
-        In the list of ranges, the last item can be None to indicate that
-        it should go to the end of the file, and the first item can be
-        negative to indicate that it should start from an offset from the
-        end.  If you give a length then this will not occur (negative
-        numbers and offsets will be resolved).
-
-        If length is given, and any range is not value, then None is
-        returned.
-        """
-        result = []
-        for begin, end in ranges:
-            if begin < 0:
-                if length is None:
-                    result.append((begin, None))
-                    continue
-                else:
-                    begin = length - begin
-                    end = length
-            if begin is None:
-                begin = 0
-            if end is None and length is not None:
-                end = length
-            if length is not None and end is not None and end > length:
-                return None
-            if end is not None:
-                end -= 1
-            result.append((begin, end))
-        return result
-    bytes_to_python_ranges = staticmethod(bytes_to_python_ranges)
-    
-    #@staticmethod
-    def python_ranges_to_bytes(ranges):
-        """
-        Converts a Python-style list of ranges to what serialize_bytes
-        expects.
-
-        This is the inverse of bytes_to_python_ranges
-        """
-        result = []
-        for begin, end in ranges:
-            if end is None:
-                result.append((begin, None))
-            else:
-                result.append((begin, end+1))
-        return result
-    python_ranges_to_bytes = staticmethod(python_ranges_to_bytes)
-
-class ContentRange(object):
-
-    """
-    Represents the Content-Range header
-
-    This header is ``start-stop/length``, where stop and length can be
-    ``*`` (represented as None in the attributes).
-    """
-
-    def __init__(self, start, stop, length):
-        assert start >= 0, "Bad start: %r" % start
-        assert stop is None or (stop >= 0 and stop >= start), (
-            "Bad stop: %r" % stop)
-        self.start = start
-        self.stop = stop
-        self.length = length
-
-    def __repr__(self):
-        return '<%s %s>' % (
-            self.__class__.__name__,
-            self)
-
-    def __str__(self):
-        if self.stop is None:
-            stop = '*'
-        else:
-            stop = self.stop + 1
-        if self.length is None:
-            length = '*'
-        else:
-            length = self.length
-        return 'bytes %s-%s/%s' % (self.start, stop, length)
-
-    def __iter__(self):
-        """
-        Mostly so you can unpack this, like:
-
-            start, stop, length = res.content_range
-        """
-        return iter([self.start, self.stop, self.length])
-
-    #@classmethod
-    def parse(cls, value):
-        """
-        Parse the header.  May return None if it cannot parse.
-        """
-        if value is None:
-            return None
-        value = value.strip()
-        if not value.startswith('bytes '):
-            # Unparseable
-            return None
-        value = value[len('bytes '):].strip()
-        if '/' not in value:
-            # Invalid, no length given
-            return None
-        range, length = value.split('/', 1)
-        if '-' not in range:
-            # Invalid, no range
-            return None
-        start, end = range.split('-', 1)
-        try:
-            start = int(start)
-            if end == '*':
-                end = None
-            else:
-                end = int(end)
-            if length == '*':
-                length = None
-            else:
-                length = int(length)
-        except ValueError:
-            # Parse problem
-            return None
-        if end is None:
-            return cls(start, None, length)
-        else:
-            return cls(start, end-1, length)
-    parse = classmethod(parse)
-    
diff --git a/lib/webob/cachecontrol.py b/lib/webob/cachecontrol.py
@@ -1,169 +0,0 @@
-"""
-Represents the Cache-Control header
-"""
-
-import re
-from webob.updatedict import UpdateDict
-try:
-    sorted
-except NameError:
-    from webob.compat import sorted
-
-token_re = re.compile(
-    r'([a-zA-Z][a-zA-Z_-]*)\s*(?:=(?:"([^"]*)"|([^ \t",;]*)))?')
-need_quote_re = re.compile(r'[^a-zA-Z0-9._-]')
-
-class exists_property(object):
-    """
-    Represents a property that either is listed in the Cache-Control
-    header, or is not listed (has no value)
-    """
-    def __init__(self, prop, type=None):
-        self.prop = prop
-        self.type = type
-
-    def __get__(self, obj, type=None):
-        if obj is None:
-            return self
-        return self.prop in obj.properties
-    def __set__(self, obj, value):
-        if (self.type is not None
-            and self.type != obj.type):
-            raise AttributeError(
-                "The property %s only applies to %s Cache-Control" % (self.prop, self.type))
-        if value:
-            obj.properties[self.prop] = None
-        else:
-            if self.prop in obj.properties:
-                del obj.properties[self.prop]
-    def __delete__(self, obj):
-        self.__set__(obj, False)
-
-class value_property(object):
-    """
-    Represents a property that has a value in the Cache-Control header.
-
-    When no value is actually given, the value of self.none is returned.
-    """
-    def __init__(self, prop, default=None, none=None, type=None):
-        self.prop = prop
-        self.default = default
-        self.none = none
-        self.type = type
-    def __get__(self, obj, type=None):
-        if obj is None:
-            return self
-        if self.prop in obj.properties:
-            value = obj.properties[self.prop]
-            if value is None:
-                return self.none
-            else:
-                return value
-        else:
-            return self.default
-    def __set__(self, obj, value):
-        if (self.type is not None
-            and self.type != obj.type):
-            raise AttributeError(
-                "The property %s only applies to %s Cache-Control" % (self.prop, self.type))
-        if value == self.default:
-            if self.prop in obj.properties:
-                del obj.properties[self.prop]
-        elif value is True:
-            obj.properties[self.prop] = None # Empty value, but present
-        else:
-            obj.properties[self.prop] = value
-    def __delete__(self, obj):
-        if self.prop in obj.properties:
-            del obj.properties[self.prop]
-
-class CacheControl(object):
-
-    """
-    Represents the Cache-Control header.
-
-    By giving a type of ``'request'`` or ``'response'`` you can
-    control what attributes are allowed (some Cache-Control values
-    only apply to requests or responses).
-    """
-
-    def __init__(self, properties, type):
-        self.properties = properties
-        self.type = type
-
-    #@classmethod
-    def parse(cls, header, updates_to=None, type=None):
-        """
-        Parse the header, returning a CacheControl object.
-
-        The object is bound to the request or response object
-        ``updates_to``, if that is given.
-        """
-        if updates_to:
-            props = UpdateDict()
-            props.updated = updates_to
-        else:
-            props = {}
-        for match in token_re.finditer(header):
-            name = match.group(1)
-            value = match.group(2) or match.group(3) or None
-            if value:
-                try:
-                    value = int(value)
-                except ValueError:
-                    pass
-            props[name] = value
-        obj = cls(props, type=type)
-        if updates_to:
-            props.updated_args = (obj,)
-        return obj
-
-    parse = classmethod(parse)
-
-    def __repr__(self):
-        return '<CacheControl %r>' % str(self)
-
-    # Request values:
-    # no-cache shared (below)
-    # no-store shared (below)
-    # max-age shared  (below)
-    max_stale = value_property('max-stale', none='*', type='request')
-    min_fresh = value_property('min-fresh', type='request')
-    # no-transform shared (below)
-    only_if_cached = exists_property('only-if-cached', type='request')
-
-    # Response values:
-    public = exists_property('public', type='response')
-    private = value_property('private', none='*', type='response')
-    no_cache = value_property('no-cache', none='*')
-    no_store = exists_property('no-store')
-    no_transform = exists_property('no-transform')
-    must_revalidate = exists_property('must-revalidate', type='response')
-    proxy_revalidate = exists_property('proxy-revalidate', type='response')
-    max_age = value_property('max-age', none=-1)
-    s_maxage = value_property('s-maxage', type='response')
-    s_max_age = s_maxage
-
-    def __str__(self):
-        return serialize_cache_control(self.properties)
-
-    def copy(self):
-        """
-        Returns a copy of this object.
-        """
-        return self.__class__(self.properties.copy(), type=self.type)
-
-def serialize_cache_control(properties):
-    if isinstance(properties, CacheControl):
-        properties = properties.properties
-    parts = []
-    for name, value in sorted(properties.items()):
-        if value is None:
-            parts.append(name)
-            continue
-        value = str(value)
-        if need_quote_re.search(value):
-            value = '"%s"' % value
-        parts.append('%s=%s' % (name, value))
-    return ', '.join(parts)
-    
diff --git a/lib/webob/compat.py b/lib/webob/compat.py
@@ -1,23 +0,0 @@
-try:
-    # This will succeed on Python 2.4, and fail on Python 2.3.
-
-    [].sort(key=lambda: None)
-
-    def sorted(iterable, cmp=None, key=None, reverse=False):
-        l = list(iterable)
-        l.sort(cmp=cmp, key=key, reverse=reverse)
-        return l
-
-except TypeError:
-    # Implementation for Python 2.3.
-    
-    def sorted(iterable, key=None, reverse=False):
-        l = list(iterable)
-        if key:
-            l = [(key(i), i) for i in l]
-        l.sort()
-        if key:
-            l = [i[1] for i in l]
-        if reverse:
-            l.reverse()
-        return l
diff --git a/lib/webob/datastruct.py b/lib/webob/datastruct.py
@@ -1,58 +0,0 @@
-"""
-Contains some data structures.
-"""
-
-from webob.util.dictmixin import DictMixin
-
-class EnvironHeaders(DictMixin):
-    """An object that represents the headers as present in a
-    WSGI environment.
-
-    This object is a wrapper (with no internal state) for a WSGI
-    request object, representing the CGI-style HTTP_* keys as a
-    dictionary.  Because a CGI environment can only hold one value for
-    each key, this dictionary is single-valued (unlike outgoing
-    headers).
-    """
-
-    def __init__(self, environ):
-        self.environ = environ
-
-    def _trans_name(self, name):
-        key = 'HTTP_'+name.replace('-', '_').upper()
-        if key == 'HTTP_CONTENT_LENGTH':
-            key = 'CONTENT_LENGTH'
-        elif key == 'HTTP_CONTENT_TYPE':
-            key = 'CONTENT_TYPE'
-        return key
-
-    def _trans_key(self, key):
-        if key == 'CONTENT_TYPE':
-            return 'Content-Type'
-        elif key == 'CONTENT_LENGTH':
-            return 'Content-Length'
-        elif key.startswith('HTTP_'):
-            return key[5:].replace('_', '-').title()
-        else:
-            return None
-        
-    def __getitem__(self, item):
-        return self.environ[self._trans_name(item)]
-
-    def __setitem__(self, item, value):
-        self.environ[self._trans_name(item)] = value
-
-    def __delitem__(self, item):
-        del self.environ[self._trans_name(item)]
-
-    def __iter__(self):
-        for key in self.environ:
-            name = self._trans_key(key)
-            if name is not None:
-                yield name
-
-    def keys(self):
-        return list(iter(self))
-
-    def __contains__(self, item):
-        return self._trans_name(item) in self.environ
diff --git a/lib/webob/etag.py b/lib/webob/etag.py
@@ -1,214 +0,0 @@
-"""
-Does parsing of ETag-related headers: If-None-Matches, If-Matches
-
-Also If-Range parsing
-"""
-
-import webob
-
-__all__ = ['AnyETag', 'NoETag', 'ETagMatcher', 'IfRange', 'NoIfRange']
-
-class _AnyETag(object):
-    """
-    Represents an ETag of *, or a missing ETag when matching is 'safe'
-    """
-
-    def __repr__(self):
-        return '<ETag *>'
-
-    def __nonzero__(self):
-        return False
-
-    def __contains__(self, other):
-        return True
-
-    def weak_match(self, other):
-        return True
-
-    def __str__(self):
-        return '*'
-
-AnyETag = _AnyETag()
-
-class _NoETag(object):
-    """
-    Represents a missing ETag when matching is unsafe
-    """
-
-    def __repr__(self):
-        return '<No ETag>'
-
-    def __nonzero__(self):
-        return False
-
-    def __contains__(self, other):
-        return False
-
-    def weak_match(self, other):
-        return False
-
-    def __str__(self):
-        return ''
-
-NoETag = _NoETag()
-
-class ETagMatcher(object):
-
-    """
-    Represents an ETag request.  Supports containment to see if an
-    ETag matches.  You can also use
-    ``etag_matcher.weak_contains(etag)`` to allow weak ETags to match
-    (allowable for conditional GET requests, but not ranges or other
-    methods).
-    """
-
-    def __init__(self, etags, weak_etags=()):
-        self.etags = etags
-        self.weak_etags = weak_etags
-
-    def __contains__(self, other):
-        return other in self.etags
-
-    def weak_match(self, other):
-        if other.lower().startswith('w/'):
-            other = other[2:]
-        return other in self.etags or other in self.weak_etags
-
-    def __repr__(self):
-        return '<ETag %s>' % (
-            ' or '.join(self.etags))
-
-    def parse(cls, value):
-        """
-        Parse this from a header value
-        """
-        results = []
-        weak_results = []
-        while value:
-            if value.lower().startswith('w/'):
-                # Next item is weak
-                weak = True
-                value = value[2:]
-            else:
-                weak = False
-            if value.startswith('"'):
-                try:
-                    etag, rest = value[1:].split('"', 1)
-                except ValueError:
-                    etag = value.strip(' ",')
-                    rest = ''
-                else:
-                    rest = rest.strip(', ')
-            else:
-                if ',' in value:
-                    etag, rest = value.split(',', 1)
-                    rest = rest.strip()
-                else:
-                    etag = value
-                    rest = ''
-            if etag == '*':
-                return AnyETag
-            if etag:
-                if weak:
-                    weak_results.append(etag)
-                else:
-                    results.append(etag)
-            value = rest
-        return cls(results, weak_results)
-    parse = classmethod(parse)
-                    
-    def __str__(self):
-        # FIXME: should I quote these?
-        items = list(self.etags)
-        for weak in self.weak_etags:
-            items.append('W/%s' % weak)
-        return ', '.join(items)
-
-class IfRange(object):
-    """
-    Parses and represents the If-Range header, which can be
-    an ETag *or* a date
-    """
-    def __init__(self, etag=None, date=None):
-        self.etag = etag
-        self.date = date
-
-    def __repr__(self):
-        if self.etag is None:
-            etag = '*'
-        else:
-            etag = str(self.etag)
-        if self.date is None:
-            date = '*'
-        else:
-            date = webob._serialize_date(self.date)
-        return '<%s etag=%s, date=%s>' % (
-            self.__class__.__name__,
-            etag, date)
-
-    def __str__(self):
-        if self.etag is not None:
-            return str(self.etag)
-        elif self.date:
-            return webob._serialize_date(self.date)
-        else:
-            return ''
-
-    def match(self, etag=None, last_modified=None):
-        """
-        Return True if the If-Range header matches the given etag or last_modified
-        """
-        if self.date is not None:
-            if last_modified is None:
-                # Conditional with nothing to base the condition won't work
-                return False
-            return last_modified <= self.date
-        elif self.etag is not None:
-            if not etag:
-                return False
-            return etag in self.etag
-        return True
-
-    def match_response(self, response):
-        """
-        Return True if this matches the given ``webob.Response`` instance.
-        """
-        return self.match(etag=response.etag, last_modified=response.last_modified)
-
-    #@classmethod
-    def parse(cls, value):
-        """
-        Parse this from a header value.
-        """
-        date = etag = None
-        if not value:
-            etag = NoETag()
-        elif value and value.endswith(' GMT'):
-            # Must be a date
-            date = webob._parse_date(value)
-        else:
-            etag = ETagMatcher.parse(value)
-        return cls(etag=etag, date=date)
-    parse = classmethod(parse)
-
-class _NoIfRange(object):
-    """
-    Represents a missing If-Range header
-    """
-    
-    def __repr__(self):
-        return '<Empty If-Range>'
-
-    def __str__(self):
-        return ''
-
-    def __nonzero__(self):
-        return False
-
-    def match(self, etag=None, last_modified=None):
-        return True
-
-    def match_response(self, response):
-        return True
-
-NoIfRange = _NoIfRange()
diff --git a/lib/webob/exc.py b/lib/webob/exc.py
@@ -1,660 +0,0 @@
-"""
-HTTP Exception
-
-This module processes Python exceptions that relate to HTTP exceptions
-by defining a set of exceptions, all subclasses of HTTPException.
-Each exception, in addition to being a Python exception that can be
-raised and caught, is also a WSGI application and ``webob.Response``
-object.
-
-This module defines exceptions according to RFC 2068 [1]_ : codes with
-100-300 are not really errors; 400's are client errors, and 500's are
-server errors.  According to the WSGI specification [2]_ , the application
-can call ``start_response`` more then once only under two conditions:
-(a) the response has not yet been sent, or (b) if the second and
-subsequent invocations of ``start_response`` have a valid ``exc_info``
-argument obtained from ``sys.exc_info()``.  The WSGI specification then
-requires the server or gateway to handle the case where content has been
-sent and then an exception was encountered.
-
-Exception
-  HTTPException
-    HTTPOk
-      * 200 - HTTPOk
-      * 201 - HTTPCreated
-      * 202 - HTTPAccepted
-      * 203 - HTTPNonAuthoritativeInformation
-      * 204 - HTTPNoContent
-      * 205 - HTTPResetContent
-      * 206 - HTTPPartialContent
-    HTTPRedirection
-      * 300 - HTTPMultipleChoices
-      * 301 - HTTPMovedPermanently
-      * 302 - HTTPFound
-      * 303 - HTTPSeeOther
-      * 304 - HTTPNotModified
-      * 305 - HTTPUseProxy
-      * 306 - Unused (not implemented, obviously)
-      * 307 - HTTPTemporaryRedirect
-    HTTPError
-      HTTPClientError
-        * 400 - HTTPBadRequest
-        * 401 - HTTPUnauthorized
-        * 402 - HTTPPaymentRequired
-        * 403 - HTTPForbidden
-        * 404 - HTTPNotFound
-        * 405 - HTTPMethodNotAllowed
-        * 406 - HTTPNotAcceptable
-        * 407 - HTTPProxyAuthenticationRequired
-        * 408 - HTTPRequestTimeout
-        * 409 - HTTPConfict
-        * 410 - HTTPGone
-        * 411 - HTTPLengthRequired
-        * 412 - HTTPPreconditionFailed
-        * 413 - HTTPRequestEntityTooLarge
-        * 414 - HTTPRequestURITooLong
-        * 415 - HTTPUnsupportedMediaType
-        * 416 - HTTPRequestRangeNotSatisfiable
-        * 417 - HTTPExpectationFailed
-      HTTPServerError
-        * 500 - HTTPInternalServerError
-        * 501 - HTTPNotImplemented
-        * 502 - HTTPBadGateway
-        * 503 - HTTPServiceUnavailable
-        * 504 - HTTPGatewayTimeout
-        * 505 - HTTPVersionNotSupported
-
-References:
-
-.. [1] http://www.python.org/peps/pep-0333.html#error-handling
-.. [2] http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5
-
-
-"""
-
-import re
-import urlparse
-import sys
-try:
-    from string import Template
-except ImportError:
-    from webob.util.stringtemplate import Template
-import types
-from webob import Response, Request, html_escape
-
-newstyle_exceptions = issubclass(Exception, object)
-
-tag_re = re.compile(r'<.*?>', re.S)
-br_re = re.compile(r'<br.*?>', re.I|re.S)
-comment_re = re.compile(r'<!--|-->')
-
-def no_escape(value):
-    if value is None:
-        return ''
-    if not isinstance(value, basestring):
-        if hasattr(value, '__unicode__'):
-            value = unicode(value)
-        else:
-            value = str(value)
-    return value
-
-def strip_tags(value):
-    value = value.replace('\n', ' ')
-    value = value.replace('\r', '')
-    value = br_re.sub('\n', value)
-    value = comment_re.sub('', value)
-    value = tag_re.sub('', value)
-    return value
-
-class HTTPException(Exception):
-    """
-    Exception used on pre-Python-2.5, where new-style classes cannot be used as
-    an exception.
-    """
-
-    def __init__(self, message, wsgi_response):
-        Exception.__init__(self, message)
-        self.__dict__['wsgi_response'] = wsgi_response
-
-    def __call__(self, environ, start_response):
-        return self.wsgi_response(environ, start_response)
-
-    def exception(self):
-        return self
-    
-    exception = property(exception)
-
-    # for old style exceptions
-    if not newstyle_exceptions:
-        def __getattr__(self, attr):
-            if not attr.startswith('_'):
-                return getattr(self.wsgi_response, attr)
-            else:
-                raise AttributeError(attr)
-
-        def __setattr__(self, attr, value):
-            if attr.startswith('_') or attr in ('args',):
-                self.__dict__[attr] = value
-            else:
-                setattr(self.wsgi_response, attr, value)
-
-class WSGIHTTPException(Response, HTTPException):
-
-    ## You should set in subclasses:
-    # code = 200
-    # title = 'OK'
-    # explanation = 'why this happens'
-    # body_template_obj = Template('response template')
-    code = None
-    title = None
-    explanation = ''
-    body_template_obj = Template('''\
-${explanation}<br /><br />
-${detail}
-${html_comment}
-''')
-
-    plain_template_obj = Template('''\
-${status}
-
-${body}''')
-
-    html_template_obj = Template('''\
-<html>
- <head>
-  <title>${status}</title>
- </head>
- <body>
-  <h1>${status}</h1>
-  ${body}
- </body>
-</html>''')
-
-    ## Set this to True for responses that should have no request body
-    empty_body = False
-
-    def __init__(self, detail=None, headers=None, comment=None,
-                 body_template=None):
-        Response.__init__(self,
-                          status='%s %s' % (self.code, self.title),
-                          content_type='text/html')
-        Exception.__init__(self, detail)
-        if headers:
-            self.headers.update(headers)
-        self.detail = detail
-        self.comment = comment
-        if body_template is not None:
-            self.body_template = body_template
-            self.body_template_obj = Template(body_template)
-        if self.empty_body:
-            del self.content_type
-            del self.content_length
-
-    def _make_body(self, environ, escape):
-        args = {
-            'explanation': escape(self.explanation),
-            'detail': escape(self.detail or ''),
-            'comment': escape(self.comment or ''),
-            }
-        if self.comment:
-            args['html_comment'] = '<!-- %s -->' % escape(self.comment)
-        else:
-            args['html_comment'] = ''
-        body_tmpl = self.body_template_obj
-        if WSGIHTTPException.body_template_obj is not self.body_template_obj:
-            # Custom template; add headers to args
-            for k, v in environ.items():
-                args[k] = escape(v)
-            for k, v in self.headers.items():
-                args[k.lower()] = escape(v)
-        t_obj = self.body_template_obj
-        return t_obj.substitute(args)
-
-    def plain_body(self, environ):
-        body = self._make_body(environ, no_escape)
-        body = strip_tags(body)
-        return self.plain_template_obj.substitute(status=self.status,
-                                                  title=self.title,
-                                                  body=body)
-
-    def html_body(self, environ):
-        body = self._make_body(environ, html_escape)
-        return self.html_template_obj.substitute(status=self.status,
-                                                 body=body)
-
-    def generate_response(self, environ, start_response):
-        if self.content_length is not None:
-            del self.content_length
-        headerlist = list(self.headerlist)
-        accept = environ.get('HTTP_ACCEPT', '')
-        if accept and 'html' in accept or '*/*' in accept:
-            body = self.html_body(environ)
-            if not self.content_type:
-                headerlist.append('text/html; charset=utf8')
-        else:
-            body = self.plain_body(environ)
-            if not self.content_type:
-                headerlist.append('text/plain; charset=utf8')
-        headerlist.append(('Content-Length', str(len(body))))
-        start_response(self.status, headerlist)
-        return [body]
-
-    def __call__(self, environ, start_response):
-        if environ['REQUEST_METHOD'] == 'HEAD':
-            start_response(self.status, self.headerlist)
-            return []
-        if not self.body and not self.empty_body:
-            return self.generate_response(environ, start_response)
-        return Response.__call__(self, environ, start_response)
-
-    def wsgi_response(self):
-        return self
-    
-    wsgi_response = property(wsgi_response)
-
-    def exception(self):
-        if newstyle_exceptions:
-            return self
-        else:
-            return HTTPException(self.detail, self)
-
-    exception = property(exception)
-
-class HTTPError(WSGIHTTPException):
-    """
-    base class for status codes in the 400's and 500's
-
-    This is an exception which indicates that an error has occurred,
-    and that any work in progress should not be committed.  These are
-    typically results in the 400's and 500's.
-    """
-
-class HTTPRedirection(WSGIHTTPException):
-    """
-    base class for 300's status code (redirections)
-
-    This is an abstract base class for 3xx redirection.  It indicates
-    that further action needs to be taken by the user agent in order
-    to fulfill the request.  It does not necessarly signal an error
-    condition.
-    """
-
-class HTTPOk(WSGIHTTPException):
-    """
-    Base class for the 200's status code (successful responses)
-    """
-    code = 200
-    title = 'OK'
-
-############################################################
-## 2xx success
-############################################################
-
-class HTTPCreated(HTTPOk):
-    code = 201
-    title = 'Created'
-
-class HTTPAccepted(HTTPOk):
-    code = 202
-    title = 'Accepted'
-    explanation = 'The request is accepted for processing.'
-
-class HTTPNonAuthoritativeInformation(HTTPOk):
-    code = 203
-    title = 'Non-Authoritative Information'
-
-class HTTPNoContent(HTTPOk):
-    code = 204
-    title = 'No Content'
-    empty_body = True
-
-class HTTPResetContent(HTTPOk):
-    code = 205
-    title = 'Reset Content'
-    empty_body = True
-
-class HTTPPartialContent(HTTPOk):
-    code = 206
-    title = 'Partial Content'
-
-## FIXME: add 207 Multi-Status (but it's complicated)
-
-############################################################
-## 3xx redirection
-############################################################
-
-class _HTTPMove(HTTPRedirection):
-    """
-    redirections which require a Location field
-
-    Since a 'Location' header is a required attribute of 301, 302, 303,
-    305 and 307 (but not 304), this base class provides the mechanics to
-    make this easy.
-
-    You can provide a location keyword argument to set the location
-    immediately.  You may also give ``add_slash=True`` if you want to
-    redirect to the same URL as the request, except with a ``/`` added
-    to the end.
-
-    Relative URLs in the location will be resolved to absolute.
-    """
-    explanation = 'The resource has been moved to'
-    body_template_obj = Template('''\
-${explanation} <a href="${location}">${location}</a>;
-you should be redirected automatically.
-${detail}
-${html_comment}''')
-
-    def __init__(self, detail=None, headers=None, comment=None,
-                 body_template=None, location=None, add_slash=False):
-        super(_HTTPMove, self).__init__(
-            detail=detail, headers=headers, comment=comment,
-            body_template=body_template)
-        if location is not None:
-            self.location = location
-            if add_slash:
-                raise TypeError(
-                    "You can only provide one of the arguments location and add_slash")
-        self.add_slash = add_slash
-
-    def __call__(self, environ, start_response):
-        req = Request(environ)
-        if self.add_slash:
-            url = req.path_url
-            url += '/'
-            if req.environ.get('QUERY_STRING'):
-                url += '?' + req.environ['QUERY_STRING']
-            self.location = url
-        self.location = urlparse.urljoin(req.path_url, self.location)
-        return super(_HTTPMove, self).__call__(
-            environ, start_response)
-    
-class HTTPMultipleChoices(_HTTPMove):
-    code = 300
-    title = 'Multiple Choices'
-
-class HTTPMovedPermanently(_HTTPMove):
-    code = 301
-    title = 'Moved Permanently'
-
-class HTTPFound(_HTTPMove):
-    code = 302
-    title = 'Found'
-    explanation = 'The resource was found at'
-
-# This one is safe after a POST (the redirected location will be
-# retrieved with GET):
-class HTTPSeeOther(_HTTPMove):
-    code = 303
-    title = 'See Other'
-
-class HTTPNotModified(HTTPRedirection):
-    # FIXME: this should include a date or etag header
-    code = 304
-    title = 'Not Modified'
-    empty_body = True
-
-class HTTPUseProxy(_HTTPMove):
-    # Not a move, but looks a little like one
-    code = 305
-    title = 'Use Proxy'
-    explanation = (
-        'The resource must be accessed through a proxy located at')
-
-class HTTPTemporaryRedirect(_HTTPMove):
-    code = 307
-    title = 'Temporary Redirect'
-
-############################################################
-## 4xx client error
-############################################################
-
-class HTTPClientError(HTTPError):
-    """
-    base class for the 400's, where the client is in error
-
-    This is an error condition in which the client is presumed to be
-    in-error.  This is an expected problem, and thus is not considered
-    a bug.  A server-side traceback is not warranted.  Unless specialized,
-    this is a '400 Bad Request'
-    """
-    code = 400
-    title = 'Bad Request'
-    explanation = ('The server could not comply with the request since\r\n'
-                   'it is either malformed or otherwise incorrect.\r\n')
-
-class HTTPBadRequest(HTTPClientError):
-    pass
-
-class HTTPUnauthorized(HTTPClientError):
-    code = 401
-    title = 'Unauthorized'
-    explanation = (
-        'This server could not verify that you are authorized to\r\n'
-        'access the document you requested.  Either you supplied the\r\n'
-        'wrong credentials (e.g., bad password), or your browser\r\n'
-        'does not understand how to supply the credentials required.\r\n')
-
-class HTTPPaymentRequired(HTTPClientError):
-    code = 402
-    title = 'Payment Required'
-    explanation = ('Access was denied for financial reasons.')
-
-class HTTPForbidden(HTTPClientError):
-    code = 403
-    title = 'Forbidden'
-    explanation = ('Access was denied to this resource.')
-
-class HTTPNotFound(HTTPClientError):
-    code = 404
-    title = 'Not Found'
-    explanation = ('The resource could not be found.')
-
-class HTTPMethodNotAllowed(HTTPClientError):
-    code = 405
-    title = 'Method Not Allowed'
-    # override template since we need an environment variable
-    body_template_obj = Template('''\
-The method ${REQUEST_METHOD} is not allowed for this resource. <br /><br />
-${detail}''')
-
-class HTTPNotAcceptable(HTTPClientError):
-    code = 406
-    title = 'Not Acceptable'
-    # override template since we need an environment variable
-    template = Template('''\
-The resource could not be generated that was acceptable to your browser
-(content of type ${HTTP_ACCEPT}. <br /><br />
-${detail}''')
-
-class HTTPProxyAuthenticationRequired(HTTPClientError):
-    code = 407
-    title = 'Proxy Authentication Required'
-    explanation = ('Authentication with a local proxy is needed.')
-
-class HTTPRequestTimeout(HTTPClientError):
-    code = 408
-    title = 'Request Timeout'
-    explanation = ('The server has waited too long for the request to '
-                   'be sent by the client.')
-
-class HTTPConflict(HTTPClientError):
-    code = 409
-    title = 'Conflict'
-    explanation = ('There was a conflict when trying to complete '
-                   'your request.')
-
-class HTTPGone(HTTPClientError):
-    code = 410
-    title = 'Gone'
-    explanation = ('This resource is no longer available.  No forwarding '
-                   'address is given.')
-
-class HTTPLengthRequired(HTTPClientError):
-    code = 411
-    title = 'Length Required'
-    explanation = ('Content-Length header required.')
-
-class HTTPPreconditionFailed(HTTPClientError):
-    code = 412
-    title = 'Precondition Failed'
-    explanation = ('Request precondition failed.')
-
-class HTTPRequestEntityTooLarge(HTTPClientError):
-    code = 413
-    title = 'Request Entity Too Large'
-    explanation = ('The body of your request was too large for this server.')
-
-class HTTPRequestURITooLong(HTTPClientError):
-    code = 414
-    title = 'Request-URI Too Long'
-    explanation = ('The request URI was too long for this server.')
-
-class HTTPUnsupportedMediaType(HTTPClientError):
-    code = 415
-    title = 'Unsupported Media Type'
-    # override template since we need an environment variable
-    template_obj = Template('''\
-The request media type ${CONTENT_TYPE} is not supported by this server.
-<br /><br />
-${detail}''')
-
-class HTTPRequestRangeNotSatisfiable(HTTPClientError):
-    code = 416
-    title = 'Request Range Not Satisfiable'
-    explanation = ('The Range requested is not available.')
-
-class HTTPExpectationFailed(HTTPClientError):
-    code = 417
-    title = 'Expectation Failed'
-    explanation = ('Expectation failed.')
-
-class HTTPUnprocessableEntity(HTTPClientError):
-    ## Note: from WebDAV
-    code = 422
-    title = 'Unprocessable Entity'
-    explanation = 'Unable to process the contained instructions'
-
-class HTTPLocked(HTTPClientError):
-    ## Note: from WebDAV
-    code = 423
-    title = 'Locked'
-    explanation = ('The resource is locked')
-
-class HTTPFailedDependency(HTTPClientError):
-    ## Note: from WebDAV
-    code = 424
-    title = 'Failed Dependency'
-    explanation = ('The method could not be performed because the requested '
-                   'action dependended on another action and that action failed')
-
-############################################################
-## 5xx Server Error
-############################################################
-#  Response status codes beginning with the digit "5" indicate cases in
-#  which the server is aware that it has erred or is incapable of
-#  performing the request. Except when responding to a HEAD request, the
-#  server SHOULD include an entity containing an explanation of the error
-#  situation, and whether it is a temporary or permanent condition. User
-#  agents SHOULD display any included entity to the user. These response
-#  codes are applicable to any request method.
-
-class HTTPServerError(HTTPError):
-    """
-    base class for the 500's, where the server is in-error
-
-    This is an error condition in which the server is presumed to be
-    in-error.  This is usually unexpected, and thus requires a traceback;
-    ideally, opening a support ticket for the customer. Unless specialized,
-    this is a '500 Internal Server Error'
-    """
-    code = 500
-    title = 'Internal Server Error'
-    explanation = (
-      'The server has either erred or is incapable of performing\r\n'
-      'the requested operation.\r\n')
-
-class HTTPInternalServerError(HTTPServerError):
-    pass
-
-class HTTPNotImplemented(HTTPServerError):
-    code = 501
-    title = 'Not Implemented'
-    template = Template('''
-The request method ${REQUEST_METHOD} is not implemented for this server. <br /><br />
-${detail}''')
-
-class HTTPBadGateway(HTTPServerError):
-    code = 502
-    title = 'Bad Gateway'
-    explanation = ('Bad gateway.')
-
-class HTTPServiceUnavailable(HTTPServerError):
-    code = 503
-    title = 'Service Unavailable'
-    explanation = ('The server is currently unavailable. '
-                   'Please try again at a later time.')
-
-class HTTPGatewayTimeout(HTTPServerError):
-    code = 504
-    title = 'Gateway Timeout'
-    explanation = ('The gateway has timed out.')
-
-class HTTPVersionNotSupported(HTTPServerError):
-    code = 505
-    title = 'HTTP Version Not Supported'
-    explanation = ('The HTTP version is not supported.')
-
-class HTTPInsufficientStorage(HTTPServerError):
-    code = 507
-    title = 'Insufficient Storage'
-    explanation = ('There was not enough space to save the resource')
-
-class HTTPExceptionMiddleware(object):
-    """
-    Middleware that catches exceptions in the sub-application.  This
-    does not catch exceptions in the app_iter; only during the initial
-    calling of the application.
-
-    This should be put *very close* to applications that might raise
-    these exceptions.  This should not be applied globally; letting
-    *expected* exceptions raise through the WSGI stack is dangerous.
-    """
-
-    def __init__(self, application):
-        self.application = application
-    def __call__(self, environ, start_response):
-        try:
-            return self.application(environ, start_response)
-        except HTTPException, exc:
-            parent_exc_info = sys.exc_info()
-            def repl_start_response(status, headers, exc_info=None):
-                if exc_info is None:
-                    exc_info = parent_exc_info
-                return start_response(status, headers, exc_info)
-            return exc(environ, repl_start_response)
-
-try:
-    from paste import httpexceptions
-except ImportError:
-    # Without Paste we don't need to do this fixup
-    pass
-else:
-    for name in dir(httpexceptions):
-        obj = globals().get(name)
-        if (obj and isinstance(obj, type) and issubclass(obj, HTTPException)
-            and obj is not HTTPException
-            and obj is not WSGIHTTPException):
-            obj.__bases__ = obj.__bases__ + (getattr(httpexceptions, name),)
-    del name, obj, httpexceptions
-
-__all__ = ['HTTPExceptionMiddleware', 'status_map']
-status_map={}
-for name, value in globals().items():
-    if (isinstance(value, (type, types.ClassType)) and issubclass(value, HTTPException)
-        and not name.startswith('_')):
-        __all__.append(name)
-        if getattr(value, 'code', None):
-            status_map[value.code]=value
-del name, value
-
diff --git a/lib/webob/headerdict.py b/lib/webob/headerdict.py
@@ -1,110 +0,0 @@
-"""
-Represents the response header list as a dictionary-like object.
-"""
-
-from webob.multidict import MultiDict
-try:
-    reversed
-except NameError:
-    from webob.util.reversed import reversed
-
-class HeaderDict(MultiDict):
-
-    """
-    Like a MultiDict, this wraps a list.  Keys are normalized
-    for case and whitespace.
-    """
-
-    def normalize(self, key):
-        return str(key).lower().strip()
-
-    def __getitem__(self, key):
-        normalize = self.normalize
-        key = normalize(key)
-        for k, v in reversed(self._items):
-            if normalize(k) == key:
-                return v
-        raise KeyError(key)
-
-    def getall(self, key):
-        normalize = self.normalize
-        key = normalize(key)
-        result = []
-        for k, v in self._items:
-            if normalize(k) == key:
-                result.append(v)
-        return result
-
-    def mixed(self):
-        result = {}
-        multi = {}
-        normalize = self.normalize
-        for key, value in self.iteritems():
-            key = normalize(key)
-            if key in result:
-                if key in multi:
-                    result[key].append(value)
-                else:
-                    result[key] = [result[key], value]
-                    multi[key] = None
-            else:
-                result[key] = value
-        return result
-
-    def dict_of_lists(self):
-        result = {}
-        normalize = self.normalize
-        for key, value in self.iteritems():
-            key = normalize(key)
-            if key in result:
-                result[key].append(value)
-            else:
-                result[key] = [value]
-        return result
-
-    def __delitem__(self, key):
-        normalize = self.normalize
-        key = normalize(key)
-        items = self._items
-        found = False
-        for i in range(len(items)-1, -1, -1):
-            if normalize(items[i][0]) == key:
-                del items[i]
-                found = True
-        if not found:
-            raise KeyError(key)
-
-    def __contains__(self, key):
-        normalize = self.normalize
-        key = normalize(key)
-        for k, v in self._items:
-            if normalize(k) == key:
-                return True
-        return False
-
-    has_key = __contains__
-
-    def setdefault(self, key, default=None):
-        normalize = self.normalize
-        c_key = normalize(key)
-        for k, v in self._items:
-            if normalize(k) == c_key:
-                return v
-        self._items.append((key, default))
-        return default
-
-    def pop(self, key, *args):
-        if len(args) > 1:
-            raise TypeError, "pop expected at most 2 arguments, got "\
-                              + repr(1 + len(args))
-        key = self.normalize(key)
-        for i in range(len(self._items)):
-            if self.normalize(self._items[i][0]) == key:
-                v = self._items[i][1]
-                del self._items[i]
-                return v
-        if args:
-            return args[0]
-        else:
-            raise KeyError(key)
-
diff --git a/lib/webob/multidict.py b/lib/webob/multidict.py
@@ -1,606 +0,0 @@
-# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
-# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-"""
-Gives a multi-value dictionary object (MultiDict) plus several wrappers
-"""
-import cgi
-import copy
-import sys
-from webob.util.dictmixin import DictMixin
-try:
-    reversed
-except NameError:
-    from webob.util.reversed import reversed
-
-__all__ = ['MultiDict', 'UnicodeMultiDict', 'NestedMultiDict', 'NoVars']
-
-class MultiDict(DictMixin):
-
-    """
-    An ordered dictionary that can have multiple values for each key.
-    Adds the methods getall, getone, mixed, and add to the normal
-    dictionary interface.
-    """
-
-    def __init__(self, *args, **kw):
-        if len(args) > 1:
-            raise TypeError(
-                "MultiDict can only be called with one positional argument")
-        if args:
-            if hasattr(args[0], 'iteritems'):
-                items = list(args[0].iteritems())
-            elif hasattr(args[0], 'items'):
-                items = args[0].items()
-            else:
-                items = list(args[0])
-            self._items = items
-        else:
-            self._items = []
-        self._items.extend(kw.iteritems())
-
-    #@classmethod
-    def view_list(cls, lst):
-        """
-        Create a dict that is a view on the given list
-        """
-        if not isinstance(lst, list):
-            raise TypeError(
-                "%s.view_list(obj) takes only actual list objects, not %r"
-                % (cls.__name__, lst))
-        obj = cls()
-        obj._items = lst
-        return obj
-
-    view_list = classmethod(view_list)
-
-    #@classmethod
-    def from_fieldstorage(cls, fs):
-        """
-        Create a dict from a cgi.FieldStorage instance
-        """
-        obj = cls()
-        if fs.list:
-            # fs.list can be None when there's nothing to parse
-            for field in fs.list:
-                if field.filename:
-                    obj.add(field.name, field)
-                else:
-                    obj.add(field.name, field.value)
-        return obj
-
-    from_fieldstorage = classmethod(from_fieldstorage)
-
-    def __getitem__(self, key):
-        for k, v in reversed(self._items):
-            if k == key:
-                return v
-        raise KeyError(key)
-
-    def __setitem__(self, key, value):
-        try:
-            del self[key]
-        except KeyError:
-            pass
-        self._items.append((key, value))
-
-    def add(self, key, value):
-        """
-        Add the key and value, not overwriting any previous value.
-        """
-        self._items.append((key, value))
-
-    def getall(self, key):
-        """
-        Return a list of all values matching the key (may be an empty list)
-        """
-        result = []
-        for k, v in self._items:
-            if key == k:
-                result.append(v)
-        return result
-
-    def getone(self, key):
-        """
-        Get one value matching the key, raising a KeyError if multiple
-        values were found.
-        """
-        v = self.getall(key)
-        if not v:
-            raise KeyError('Key not found: %r' % key)
-        if len(v) > 1:
-            raise KeyError('Multiple values match %r: %r' % (key, v))
-        return v[0]
-
-    def mixed(self):
-        """
-        Returns a dictionary where the values are either single
-        values, or a list of values when a key/value appears more than
-        once in this dictionary.  This is similar to the kind of
-        dictionary often used to represent the variables in a web
-        request.
-        """
-        result = {}
-        multi = {}
-        for key, value in self.iteritems():
-            if key in result:
-                # We do this to not clobber any lists that are
-                # *actual* values in this dictionary:
-                if key in multi:
-                    result[key].append(value)
-                else:
-                    result[key] = [result[key], value]
-                    multi[key] = None
-            else:
-                result[key] = value
-        return result
-
-    def dict_of_lists(self):
-        """
-        Returns a dictionary where each key is associated with a
-        list of values.
-        """
-        result = {}
-        for key, value in self.iteritems():
-            if key in result:
-                result[key].append(value)
-            else:
-                result[key] = [value]
-        return result
-
-    def __delitem__(self, key):
-        items = self._items
-        found = False
-        for i in range(len(items)-1, -1, -1):
-            if items[i][0] == key:
-                del items[i]
-                found = True
-        if not found:
-            raise KeyError(key)
-
-    def __contains__(self, key):
-        for k, v in self._items:
-            if k == key:
-                return True
-        return False
-
-    has_key = __contains__
-
-    def clear(self):
-        self._items = []
-
-    def copy(self):
-        return self.__class__(self)
-
-    def setdefault(self, key, default=None):
-        for k, v in self._items:
-            if key == k:
-                return v
-        self._items.append((key, default))
-        return default
-
-    def pop(self, key, *args):
-        if len(args) > 1:
-            raise TypeError, "pop expected at most 2 arguments, got "\
-                              + repr(1 + len(args))
-        for i in range(len(self._items)):
-            if self._items[i][0] == key:
-                v = self._items[i][1]
-                del self._items[i]
-                return v
-        if args:
-            return args[0]
-        else:
-            raise KeyError(key)
-
-    def popitem(self):
-        return self._items.pop()
-
-    def update(self, other=None, **kwargs):
-        if other is None:
-            pass
-        elif hasattr(other, 'items'):
-            self._items.extend(other.items())
-        elif hasattr(other, 'keys'):
-            for k in other.keys():
-                self._items.append((k, other[k]))
-        else:
-            for k, v in other:
-                self._items.append((k, v))
-        if kwargs:
-            self.update(kwargs)
-
-    def __repr__(self):
-        items = ', '.join(['(%r, %r)' % v for v in self.iteritems()])
-        return '%s([%s])' % (self.__class__.__name__, items)
-
-    def __len__(self):
-        return len(self._items)
-
-    ##
-    ## All the iteration:
-    ##
-
-    def keys(self):
-        return [k for k, v in self._items]
-
-    def iterkeys(self):
-        for k, v in self._items:
-            yield k
-
-    __iter__ = iterkeys
-
-    def items(self):
-        return self._items[:]
-
-    def iteritems(self):
-        return iter(self._items)
-
-    def values(self):
-        return [v for k, v in self._items]
-
-    def itervalues(self):
-        for k, v in self._items:
-            yield v
-
-class UnicodeMultiDict(DictMixin):
-    """
-    A MultiDict wrapper that decodes returned values to unicode on the
-    fly. Decoding is not applied to assigned values.
-
-    The key/value contents are assumed to be ``str``/``strs`` or
-    ``str``/``FieldStorages`` (as is returned by the ``paste.request.parse_``
-    functions).
-
-    Can optionally also decode keys when the ``decode_keys`` argument is
-    True.
-
-    ``FieldStorage`` instances are cloned, and the clone's ``filename``
-    variable is decoded. Its ``name`` variable is decoded when ``decode_keys``
-    is enabled.
-
-    """
-    def __init__(self, multi=None, encoding=None, errors='strict',
-                 decode_keys=False):
-        self.multi = multi
-        if encoding is None:
-            encoding = sys.getdefaultencoding()
-        self.encoding = encoding
-        self.errors = errors
-        self.decode_keys = decode_keys
-
-    def _decode_key(self, key):
-        if self.decode_keys:
-            try:
-                key = key.decode(self.encoding, self.errors)
-            except AttributeError:
-                pass
-        return key
-
-    def _encode_key(self, key):
-        if self.decode_keys and isinstance(key, unicode):
-            return key.encode(self.encoding, self.errors)
-        return key
-
-    def _decode_value(self, value):
-        """
-        Decode the specified value to unicode. Assumes value is a ``str`` or
-        `FieldStorage`` object.
-
-        ``FieldStorage`` objects are specially handled.
-        """
-        if isinstance(value, cgi.FieldStorage):
-            # decode FieldStorage's field name and filename
-            value = copy.copy(value)
-            if self.decode_keys:
-                value.name = value.name.decode(self.encoding, self.errors)
-            if value.filename:
-                value.filename = value.filename.decode(self.encoding,
-                                                       self.errors)
-        elif not isinstance(value, unicode):
-            try:
-                value = value.decode(self.encoding, self.errors)
-            except AttributeError:
-                pass
-        return value
-
-    def _encode_value(self, value):
-        # FIXME: should this do the FieldStorage stuff too?
-        if isinstance(value, unicode):
-            value = value.encode(self.encoding, self.errors)
-        return value
-
-    def __getitem__(self, key):
-        return self._decode_value(self.multi.__getitem__(self._encode_key(key)))
-
-    def __setitem__(self, key, value):
-        self.multi.__setitem__(self._encode_key(key), self._encode_value(value))
-
-    def add(self, key, value):
-        """
-        Add the key and value, not overwriting any previous value.
-        """
-        self.multi.add(self._encode_key(key), self._encode_value(value))
-
-    def getall(self, key):
-        """
-        Return a list of all values matching the key (may be an empty list)
-        """
-        return [self._decode_value(v) for v in self.multi.getall(self._encode_key(key))]
-
-    def getone(self, key):
-        """
-        Get one value matching the key, raising a KeyError if multiple
-        values were found.
-        """
-        return self._decode_value(self.multi.getone(self._encode_key(key)))
-
-    def mixed(self):
-        """
-        Returns a dictionary where the values are either single
-        values, or a list of values when a key/value appears more than
-        once in this dictionary.  This is similar to the kind of
-        dictionary often used to represent the variables in a web
-        request.
-        """
-        unicode_mixed = {}
-        for key, value in self.multi.mixed().iteritems():
-            if isinstance(value, list):
-                value = [self._decode_value(value) for value in value]
-            else:
-                value = self._decode_value(value)
-            unicode_mixed[self._decode_key(key)] = value
-        return unicode_mixed
-
-    def dict_of_lists(self):
-        """
-        Returns a dictionary where each key is associated with a
-        list of values.
-        """
-        unicode_dict = {}
-        for key, value in self.multi.dict_of_lists().iteritems():
-            value = [self._decode_value(value) for value in value]
-            unicode_dict[self._decode_key(key)] = value
-        return unicode_dict
-
-    def __delitem__(self, key):
-        self.multi.__delitem__(self._encode_key(key))
-
-    def __contains__(self, key):
-        return self.multi.__contains__(self._encode_key(key))
-
-    has_key = __contains__
-
-    def clear(self):
-        self.multi.clear()
-
-    def copy(self):
-        return UnicodeMultiDict(self.multi.copy(), self.encoding, self.errors)
-
-    def setdefault(self, key, default=None):
-        return self._decode_value(self.multi.setdefault(self._encode_key(key), self._encode_value(default)))
-
-    def pop(self, key, *args):
-        return self._decode_value(self.multi.pop(self._encode_key(key), *args))
-
-    def popitem(self):
-        k, v = self.multi.popitem()
-        return (self._decode_key(k), self._decode_value(v))
-
-    def __repr__(self):
-        items = ', '.join(['(%r, %r)' % v for v in self.items()])
-        return '%s([%s])' % (self.__class__.__name__, items)
-
-    def __len__(self):
-        return self.multi.__len__()
-
-    ##
-    ## All the iteration:
-    ##
-
-    def keys(self):
-        return [self._decode_key(k) for k in self.multi.iterkeys()]
-
-    def iterkeys(self):
-        for k in self.multi.iterkeys():
-            yield self._decode_key(k)
-
-    __iter__ = iterkeys
-
-    def items(self):
-        return [(self._decode_key(k), self._decode_value(v))
-                for k, v in self.multi.iteritems()]
-
-    def iteritems(self):
-        for k, v in self.multi.iteritems():
-            yield (self._decode_key(k), self._decode_value(v))
-
-    def values(self):
-        return [self._decode_value(v) for v in self.multi.itervalues()]
-
-    def itervalues(self):
-        for v in self.multi.itervalues():
-            yield self._decode_value(v)
-
-_dummy = object()
-
-class NestedMultiDict(MultiDict):
-    """
-    Wraps several MultiDict objects, treating it as one large MultiDict
-    """
-    
-    def __init__(self, *dicts):
-        self.dicts = dicts
-
-    def __getitem__(self, key):
-        for d in self.dicts:
-            value = d.get(key, _dummy)
-            if value is not _dummy:
-                return value
-        raise KeyError(key)
-
-    def _readonly(self, *args, **kw):
-        raise KeyError("NestedMultiDict objects are read-only")
-    __setitem__ = _readonly
-    add = _readonly
-    __delitem__ = _readonly
-    clear = _readonly
-    setdefault = _readonly
-    pop = _readonly
-    popitem = _readonly
-    update = _readonly
-
-    def getall(self, key):
-        result = []
-        for d in self.dicts:
-            result.extend(d.getall(key))
-        return result
-
-    # Inherited:
-    # getone
-    # mixed
-    # dict_of_lists
-
-    def copy(self):
-        return MultiDict(self)
-
-    def __contains__(self, key):
-        for d in self.dicts:
-            if key in d:
-                return True
-        return False
-
-    has_key = __contains__
-
-    def __len__(self):
-        v = 0
-        for d in self.dicts:
-            v += len(d)
-        return v
-
-    def __nonzero__(self):
-        for d in self.dicts:
-            if d:
-                return True
-        return False
-
-    def items(self):
-        return list(self.iteritems())
-
-    def iteritems(self):
-        for d in self.dicts:
-            for item in d.iteritems():
-                yield item
-
-    def values(self):
-        return list(self.itervalues())
-
-    def itervalues(self):
-        for d in self.dicts:
-            for value in d.itervalues():
-                yield value
-
-    def keys(self):
-        return list(self.iterkeys())
-
-    def __iter__(self):
-        for d in self.dicts:
-            for key in d:
-                yield key
-
-    iterkeys = __iter__
-    
-class NoVars(object):
-    """
-    Represents no variables; used when no variables
-    are applicable.
-
-    This is read-only
-    """
-    
-    def __init__(self, reason=None):
-        self.reason = reason or 'N/A'
-
-    def __getitem__(self, key):
-        raise KeyError("No key %r: %s" % (key, self.reason))
-
-    def __setitem__(self, *args, **kw):
-        raise KeyError("Cannot add variables: %s" % self.reason)
-
-    add = __setitem__
-    setdefault = __setitem__
-    update = __setitem__
-
-    def __delitem__(self, *args, **kw):
-        raise KeyError("No keys to delete: %s" % self.reason)
-    clear = __delitem__
-    pop = __delitem__
-    popitem = __delitem__
-
-    def get(self, key, default=None):
-        return default
-
-    def getall(self, key):
-        return []
-
-    def getone(self, key):
-        return self[key]
-
-    def mixed(self):
-        return {}
-    dict_of_lists = mixed
-
-    def __contains__(self, key):
-        return False
-    has_key = __contains__
-
-    def copy(self):
-        return self
-
-    def __repr__(self):
-        return '<%s: %s>' % (self.__class__.__name__,
-                             self.reason)
-
-    def __len__(self):
-        return 0
-
-    def __cmp__(self, other):
-        return cmp({}, other)
-
-    def keys(self):
-        return []
-    def iterkeys(self):
-        return iter([])
-    __iter__ = iterkeys
-    items = keys
-    iteritems = iterkeys
-    values = keys
-    itervalues = iterkeys
-
-__test__ = {
-    'general': """
-    >>> d = MultiDict(a=1, b=2)
-    >>> d['a']
-    1
-    >>> d.getall('c')
-    []
-    >>> d.add('a', 2)
-    >>> d['a']
-    2
-    >>> d.getall('a')
-    [1, 2]
-    >>> d['b'] = 4
-    >>> d.getall('b')
-    [4]
-    >>> d.keys()
-    ['a', 'a', 'b']
-    >>> d.items()
-    [('a', 1), ('a', 2), ('b', 4)]
-    >>> d.mixed() == {'a': [1, 2], 'b': 4}
-    True
-    >>> MultiDict([('a', 'b')], c=2)
-    MultiDict([('a', 'b'), ('c', 2)])
-    """}
-
-if __name__ == '__main__':
-    import doctest
-    doctest.testmod()
diff --git a/lib/webob/statusreasons.py b/lib/webob/statusreasons.py
@@ -1,67 +0,0 @@
-"""
-Gives ``status_reasons``, a dictionary of HTTP reasons for integer status codes
-"""
-
-__all__ = ['status_reasons']
-
-status_reasons = {
-    # Status Codes
-    # Informational
-    100: 'Continue',
-    101: 'Switching Protocols',
-    102: 'Processing',
-
-    # Successful
-    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',
-
-    # Redirection
-    300: 'Multiple Choices',
-    301: 'Moved Permanently',
-    302: 'Found',
-    303: 'See Other',
-    304: 'Not Modified',
-    305: 'Use Proxy',
-    307: 'Temporary Redirect',
-
-    # Client Error
-    400: 'Bad Request',
-    401: 'Unauthorized',
-    402: 'Payment Required',
-    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',
-
-    # Server Error
-    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',
-    }
diff --git a/lib/webob/updatedict.py b/lib/webob/updatedict.py
@@ -1,41 +0,0 @@
-"""
-Dict that has a callback on all updates
-"""
-
-class UpdateDict(dict):
-    updated = None
-    updated_args = None
-    def _updated(self):
-        """
-        Assign to new_dict.updated to track updates
-        """
-        updated = self.updated
-        if updated is not None:
-            args = self.updated_args
-            if args is None:
-                args = (self,)
-            updated(*args)
-    def __setitem__(self, key, item):
-        dict.__setitem__(self, key, item)
-        self._updated()
-    def __delitem__(self, key):
-        dict.__delitem__(self, key)
-        self._updated()
-    def clear(self):
-        dict.clear(self)
-        self._updated()
-    def update(self, *args, **kw):
-        dict.update(self, *args, **kw)
-        self._updated()
-    def setdefault(self, key, failobj=None):
-        dict.setdefault(self, key, failobj)
-        self._updated()
-    def pop(self):
-        v = dict.pop(self)
-        self._updated()
-        return v
-    def popitem(self):
-        v = dict.popitem(self)
-        self._updated()
-        return v
-
diff --git a/lib/webob/util/__init__.py b/lib/webob/util/__init__.py
@@ -1 +0,0 @@
-#
diff --git a/lib/webob/util/dictmixin.py b/lib/webob/util/dictmixin.py
@@ -1,102 +0,0 @@
-"""
-A backport of UserDict.DictMixin for pre-python-2.4
-"""
-__all__ = ['DictMixin']
-
-try:
-    from UserDict import DictMixin
-except ImportError:
-    class DictMixin:
-        # Mixin defining all dictionary methods for classes that already have
-        # a minimum dictionary interface including getitem, setitem, delitem,
-        # and keys. Without knowledge of the subclass constructor, the mixin
-        # does not define __init__() or copy().  In addition to the four base
-        # methods, progressively more efficiency comes with defining
-        # __contains__(), __iter__(), and iteritems().
-
-        # second level definitions support higher levels
-        def __iter__(self):
-            for k in self.keys():
-                yield k
-        def has_key(self, key):
-            try:
-                value = self[key]
-            except KeyError:
-                return False
-            return True
-        def __contains__(self, key):
-            return self.has_key(key)
-
-        # third level takes advantage of second level definitions
-        def iteritems(self):
-            for k in self:
-                yield (k, self[k])
-        def iterkeys(self):
-            return self.__iter__()
-
-        # fourth level uses definitions from lower levels
-        def itervalues(self):
-            for _, v in self.iteritems():
-                yield v
-        def values(self):
-            return [v for _, v in self.iteritems()]
-        def items(self):
-            return list(self.iteritems())
-        def clear(self):
-            for key in self.keys():
-                del self[key]
-        def setdefault(self, key, default=None):
-            try:
-                return self[key]
-            except KeyError:
-                self[key] = default
-            return default
-        def pop(self, key, *args):
-            if len(args) > 1:
-                raise TypeError, "pop expected at most 2 arguments, got "\
-                                  + repr(1 + len(args))
-            try:
-                value = self[key]
-            except KeyError:
-                if args:
-                    return args[0]
-                raise
-            del self[key]
-            return value
-        def popitem(self):
-            try:
-                k, v = self.iteritems().next()
-            except StopIteration:
-                raise KeyError, 'container is empty'
-            del self[k]
-            return (k, v)
-        def update(self, other=None, **kwargs):
-            # Make progressively weaker assumptions about "other"
-            if other is None:
-                pass
-            elif hasattr(other, 'iteritems'):  # iteritems saves memory and lookups
-                for k, v in other.iteritems():
-                    self[k] = v
-            elif hasattr(other, 'keys'):
-                for k in other.keys():
-                    self[k] = other[k]
-            else:
-                for k, v in other:
-                    self[k] = v
-            if kwargs:
-                self.update(kwargs)
-        def get(self, key, default=None):
-            try:
-                return self[key]
-            except KeyError:
-                return default
-        def __repr__(self):
-            return repr(dict(self.iteritems()))
-        def __cmp__(self, other):
-            if other is None:
-                return 1
-            if isinstance(other, DictMixin):
-                other = dict(other.iteritems())
-            return cmp(dict(self.iteritems()), other)
-        def __len__(self):
-            return len(self.keys())
diff --git a/lib/webob/util/reversed.py b/lib/webob/util/reversed.py
@@ -1,4 +0,0 @@
-## Backport of reversed
-
-def reversed(seq):
-    return iter(list(seq)[::-1])
diff --git a/lib/webob/util/safegzip.py b/lib/webob/util/safegzip.py
@@ -1,21 +0,0 @@
-"""
-GZip that doesn't include the timestamp
-"""
-import gzip
-
-class GzipFile(gzip.GzipFile):
-
-    def _write_gzip_header(self):
-        self.fileobj.write('\037\213')             # magic header
-        self.fileobj.write('\010')                 # compression method
-        fname = self.filename[:-3]
-        flags = 0
-        if fname:
-            flags = gzip.FNAME
-        self.fileobj.write(chr(flags))
-        ## This is what WebOb patches:
-        gzip.write32u(self.fileobj, long(0))
-        self.fileobj.write('\002')
-        self.fileobj.write('\377')
-        if fname:
-            self.fileobj.write(fname + '\000')
diff --git a/lib/webob/util/stringtemplate.py b/lib/webob/util/stringtemplate.py
@@ -1,128 +0,0 @@
-"""
-Just string.Template, backported for use with Python 2.3
-"""
-####################################################################
-import re as _re
-
-class _multimap:
-    """Helper class for combining multiple mappings.
-
-    Used by .{safe_,}substitute() to combine the mapping and keyword
-    arguments.
-    """
-    def __init__(self, primary, secondary):
-        self._primary = primary
-        self._secondary = secondary
-
-    def __getitem__(self, key):
-        try:
-            return self._primary[key]
-        except KeyError:
-            return self._secondary[key]
-
-
-class _TemplateMetaclass(type):
-    pattern = r"""
-    %(delim)s(?:
-      (?P<escaped>%(delim)s) |   # Escape sequence of two delimiters
-      (?P<named>%(id)s)      |   # delimiter and a Python identifier
-      {(?P<braced>%(id)s)}   |   # delimiter and a braced identifier
-      (?P<invalid>)              # Other ill-formed delimiter exprs
-    )
-    """
-
-    def __init__(cls, name, bases, dct):
-        super(_TemplateMetaclass, cls).__init__(name, bases, dct)
-        if 'pattern' in dct:
-            pattern = cls.pattern
-        else:
-            pattern = _TemplateMetaclass.pattern % {
-                'delim' : _re.escape(cls.delimiter),
-                'id'    : cls.idpattern,
-                }
-        cls.pattern = _re.compile(pattern, _re.IGNORECASE | _re.VERBOSE)
-
-
-class Template:
-    """A string class for supporting $-substitutions."""
-    __metaclass__ = _TemplateMetaclass
-
-    delimiter = '$'
-    idpattern = r'[_a-z][_a-z0-9]*'
-
-    def __init__(self, template):
-        self.template = template
-
-    # Search for $$, $identifier, ${identifier}, and any bare $'s
-
-    def _invalid(self, mo):
-        i = mo.start('invalid')
-        lines = self.template[:i].splitlines(True)
-        if not lines:
-            colno = 1
-            lineno = 1
-        else:
-            colno = i - len(''.join(lines[:-1]))
-            lineno = len(lines)
-        raise ValueError('Invalid placeholder in string: line %d, col %d' %
-                         (lineno, colno))
-
-    def substitute(self, *args, **kws):
-        if len(args) > 1:
-            raise TypeError('Too many positional arguments')
-        if not args:
-            mapping = kws
-        elif kws:
-            mapping = _multimap(kws, args[0])
-        else:
-            mapping = args[0]
-        # Helper function for .sub()
-        def convert(mo):
-            # Check the most common path first.
-            named = mo.group('named') or mo.group('braced')
-            if named is not None:
-                val = mapping[named]
-                # We use this idiom instead of str() because the latter will
-                # fail if val is a Unicode containing non-ASCII characters.
-                return '%s' % val
-            if mo.group('escaped') is not None:
-                return self.delimiter
-            if mo.group('invalid') is not None:
-                self._invalid(mo)
-            raise ValueError('Unrecognized named group in pattern',
-                             self.pattern)
-        return self.pattern.sub(convert, self.template)
-
-    def safe_substitute(self, *args, **kws):
-        if len(args) > 1:
-            raise TypeError('Too many positional arguments')
-        if not args:
-            mapping = kws
-        elif kws:
-            mapping = _multimap(kws, args[0])
-        else:
-            mapping = args[0]
-        # Helper function for .sub()
-        def convert(mo):
-            named = mo.group('named')
-            if named is not None:
-                try:
-                    # We use this idiom instead of str() because the latter
-                    # will fail if val is a Unicode containing non-ASCII
-                    return '%s' % mapping[named]
-                except KeyError:
-                    return self.delimiter + named
-            braced = mo.group('braced')
-            if braced is not None:
-                try:
-                    return '%s' % mapping[braced]
-                except KeyError:
-                    return self.delimiter + '{' + braced + '}'
-            if mo.group('escaped') is not None:
-                return self.delimiter
-            if mo.group('invalid') is not None:
-                return self.delimiter
-            raise ValueError('Unrecognized named group in pattern',
-                             self.pattern)
-        return self.pattern.sub(convert, self.template)
-