07c3f5360b22 flask

Unbundle cherrypy and webpy.
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Fri, 11 Jun 2010 20:08:34 -0400
parents b0482e5ac2bf
children 46b413229d3d
branches/tags flask
files bundled/cherrypy/MANIFEST.in bundled/cherrypy/README.txt bundled/cherrypy/cherrypy/LICENSE.txt bundled/cherrypy/cherrypy/__init__.py bundled/cherrypy/cherrypy/_cpchecker.py bundled/cherrypy/cherrypy/_cpconfig.py bundled/cherrypy/cherrypy/_cpdispatch.py bundled/cherrypy/cherrypy/_cperror.py bundled/cherrypy/cherrypy/_cplogging.py bundled/cherrypy/cherrypy/_cpmodpy.py bundled/cherrypy/cherrypy/_cpnative_server.py bundled/cherrypy/cherrypy/_cpreqbody.py bundled/cherrypy/cherrypy/_cprequest.py bundled/cherrypy/cherrypy/_cpserver.py bundled/cherrypy/cherrypy/_cpthreadinglocal.py bundled/cherrypy/cherrypy/_cptools.py bundled/cherrypy/cherrypy/_cptree.py bundled/cherrypy/cherrypy/_cpwsgi.py bundled/cherrypy/cherrypy/_cpwsgi_server.py bundled/cherrypy/cherrypy/cherryd bundled/cherrypy/cherrypy/favicon.ico bundled/cherrypy/cherrypy/lib/__init__.py bundled/cherrypy/cherrypy/lib/auth.py bundled/cherrypy/cherrypy/lib/auth_basic.py bundled/cherrypy/cherrypy/lib/auth_digest.py bundled/cherrypy/cherrypy/lib/caching.py bundled/cherrypy/cherrypy/lib/covercp.py bundled/cherrypy/cherrypy/lib/cptools.py bundled/cherrypy/cherrypy/lib/encoding.py bundled/cherrypy/cherrypy/lib/http.py bundled/cherrypy/cherrypy/lib/httpauth.py bundled/cherrypy/cherrypy/lib/httputil.py bundled/cherrypy/cherrypy/lib/jsontools.py bundled/cherrypy/cherrypy/lib/profiler.py bundled/cherrypy/cherrypy/lib/reprconf.py bundled/cherrypy/cherrypy/lib/sessions.py bundled/cherrypy/cherrypy/lib/static.py bundled/cherrypy/cherrypy/lib/xmlrpc.py bundled/cherrypy/cherrypy/process/__init__.py bundled/cherrypy/cherrypy/process/plugins.py bundled/cherrypy/cherrypy/process/servers.py bundled/cherrypy/cherrypy/process/win32.py bundled/cherrypy/cherrypy/process/wspbus.py bundled/cherrypy/cherrypy/scaffold/__init__.py bundled/cherrypy/cherrypy/scaffold/apache-fcgi.conf bundled/cherrypy/cherrypy/scaffold/example.conf bundled/cherrypy/cherrypy/scaffold/site.conf bundled/cherrypy/cherrypy/scaffold/static/made_with_cherrypy_small.png bundled/cherrypy/cherrypy/test/__init__.py bundled/cherrypy/cherrypy/test/benchmark.py bundled/cherrypy/cherrypy/test/checkerdemo.py bundled/cherrypy/cherrypy/test/fcgi.conf bundled/cherrypy/cherrypy/test/helper.py bundled/cherrypy/cherrypy/test/logtest.py bundled/cherrypy/cherrypy/test/modfcgid.py bundled/cherrypy/cherrypy/test/modpy.py bundled/cherrypy/cherrypy/test/modwsgi.py bundled/cherrypy/cherrypy/test/py25.py bundled/cherrypy/cherrypy/test/sessiondemo.py bundled/cherrypy/cherrypy/test/static/dirback.jpg bundled/cherrypy/cherrypy/test/static/index.html bundled/cherrypy/cherrypy/test/style.css bundled/cherrypy/cherrypy/test/test.pem bundled/cherrypy/cherrypy/test/test.py bundled/cherrypy/cherrypy/test/test_auth_basic.py bundled/cherrypy/cherrypy/test/test_auth_digest.py bundled/cherrypy/cherrypy/test/test_bus.py bundled/cherrypy/cherrypy/test/test_caching.py bundled/cherrypy/cherrypy/test/test_config.py bundled/cherrypy/cherrypy/test/test_config_server.py bundled/cherrypy/cherrypy/test/test_conn.py bundled/cherrypy/cherrypy/test/test_core.py bundled/cherrypy/cherrypy/test/test_dynamicobjectmapping.py bundled/cherrypy/cherrypy/test/test_encoding.py bundled/cherrypy/cherrypy/test/test_etags.py bundled/cherrypy/cherrypy/test/test_http.py bundled/cherrypy/cherrypy/test/test_httpauth.py bundled/cherrypy/cherrypy/test/test_httplib.py bundled/cherrypy/cherrypy/test/test_json.py bundled/cherrypy/cherrypy/test/test_logging.py bundled/cherrypy/cherrypy/test/test_mime.py bundled/cherrypy/cherrypy/test/test_misc_tools.py bundled/cherrypy/cherrypy/test/test_objectmapping.py bundled/cherrypy/cherrypy/test/test_proxy.py bundled/cherrypy/cherrypy/test/test_refleaks.py bundled/cherrypy/cherrypy/test/test_request_obj.py bundled/cherrypy/cherrypy/test/test_routes.py bundled/cherrypy/cherrypy/test/test_session.py bundled/cherrypy/cherrypy/test/test_sessionauthenticate.py bundled/cherrypy/cherrypy/test/test_states.py bundled/cherrypy/cherrypy/test/test_states_demo.py bundled/cherrypy/cherrypy/test/test_static.py bundled/cherrypy/cherrypy/test/test_tools.py bundled/cherrypy/cherrypy/test/test_tutorials.py bundled/cherrypy/cherrypy/test/test_virtualhost.py bundled/cherrypy/cherrypy/test/test_wsgi_ns.py bundled/cherrypy/cherrypy/test/test_wsgi_vhost.py bundled/cherrypy/cherrypy/test/test_wsgiapps.py bundled/cherrypy/cherrypy/test/test_xmlrpc.py bundled/cherrypy/cherrypy/test/webtest.py bundled/cherrypy/cherrypy/tutorial/README.txt bundled/cherrypy/cherrypy/tutorial/__init__.py bundled/cherrypy/cherrypy/tutorial/bonus-sqlobject.py bundled/cherrypy/cherrypy/tutorial/custom_error.html bundled/cherrypy/cherrypy/tutorial/pdf_file.pdf bundled/cherrypy/cherrypy/tutorial/tut01_helloworld.py bundled/cherrypy/cherrypy/tutorial/tut02_expose_methods.py bundled/cherrypy/cherrypy/tutorial/tut03_get_and_post.py bundled/cherrypy/cherrypy/tutorial/tut04_complex_site.py bundled/cherrypy/cherrypy/tutorial/tut05_derived_objects.py bundled/cherrypy/cherrypy/tutorial/tut06_default_method.py bundled/cherrypy/cherrypy/tutorial/tut07_sessions.py bundled/cherrypy/cherrypy/tutorial/tut08_generators_and_yield.py bundled/cherrypy/cherrypy/tutorial/tut09_files.py bundled/cherrypy/cherrypy/tutorial/tut10_http_errors.py bundled/cherrypy/cherrypy/tutorial/tutorial.conf bundled/cherrypy/cherrypy/wsgiserver/__init__.py bundled/cherrypy/cherrypy/wsgiserver/ssl_builtin.py bundled/cherrypy/cherrypy/wsgiserver/ssl_pyopenssl.py bundled/cherrypy/docs/cherryd.1 bundled/cherrypy/ez_setup.py bundled/cherrypy/make-sdist bundled/cherrypy/setup.py bundled/cherrypy/visuals/cherrypy_logo_big.png bundled/cherrypy/visuals/cherrypy_logo_small.jpg bundled/cherrypy/visuals/favicon.ico bundled/cherrypy/visuals/made_with_cherrypy_big.png bundled/cherrypy/visuals/made_with_cherrypy_small.png bundled/webpy/.gitignore bundled/webpy/ChangeLog.txt bundled/webpy/LICENSE.txt bundled/webpy/experimental/background.py bundled/webpy/experimental/migration.py bundled/webpy/experimental/pwt.py bundled/webpy/experimental/untwisted.py bundled/webpy/setup.py bundled/webpy/test/README bundled/webpy/test/__init__.py bundled/webpy/test/alltests.py bundled/webpy/test/application.py bundled/webpy/test/browser.py bundled/webpy/test/db.py bundled/webpy/test/doctests.py bundled/webpy/test/session.py bundled/webpy/test/webtest.py bundled/webpy/tools/_makedoc.py bundled/webpy/tools/makedoc.py bundled/webpy/tools/markdown.py bundled/webpy/web/__init__.py bundled/webpy/web/application.py bundled/webpy/web/browser.py bundled/webpy/web/contrib/__init__.py bundled/webpy/web/contrib/template.py bundled/webpy/web/db.py bundled/webpy/web/debugerror.py bundled/webpy/web/form.py bundled/webpy/web/http.py bundled/webpy/web/httpserver.py bundled/webpy/web/net.py bundled/webpy/web/session.py bundled/webpy/web/template.py bundled/webpy/web/test.py bundled/webpy/web/utils.py bundled/webpy/web/webapi.py bundled/webpy/web/webopenid.py bundled/webpy/web/wsgi.py bundled/webpy/web/wsgiserver/LICENSE.txt bundled/webpy/web/wsgiserver/__init__.py

Changes

--- a/bundled/cherrypy/MANIFEST.in	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-include cherrypy/cherryd
-include cherrypy/favicon.ico
-include cherrypy/LICENSE.txt
-include cherrypy/scaffold/*.conf
-include cherrypy/scaffold/static/*.png
-include cherrypy/test/style.css
-include cherrypy/test/test.pem
-include cherrypy/test/static/*.html
-include cherrypy/test/static/*.jpg
-include cherrypy/tutorial/*.conf
-include cherrypy/tutorial/*.pdf
-include cherrypy/tutorial/*.html
-include cherrypy/tutorial/README.txt
--- a/bundled/cherrypy/README.txt	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-* To install, change to the directory where setup.py is located and type (python-2.3 or later needed):
-
-    python setup.py install
-
-* To learn how to use it, look at the examples under cherrypy/tutorial/ or go to http://www.cherrypy.org for more info.
-
-* To run the regression tests, just go to the cherrypy/test/ directory and type:
-
-    python test.py
-
-  Or to run individual tests type:
-
-    python test.py --test_foo --test_bar
--- a/bundled/cherrypy/cherrypy/LICENSE.txt	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-Copyright (c) 2004-2009, CherryPy Team (team@cherrypy.org)
-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 of the CherryPy Team 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.
--- a/bundled/cherrypy/cherrypy/__init__.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,573 +0,0 @@
-"""CherryPy is a pythonic, object-oriented HTTP framework.
-
-
-CherryPy consists of not one, but four separate API layers.
-
-The APPLICATION LAYER is the simplest. CherryPy applications are written as
-a tree of classes and methods, where each branch in the tree corresponds to
-a branch in the URL path. Each method is a 'page handler', which receives
-GET and POST params as keyword arguments, and returns or yields the (HTML)
-body of the response. The special method name 'index' is used for paths
-that end in a slash, and the special method name 'default' is used to
-handle multiple paths via a single handler. This layer also includes:
-
- * the 'exposed' attribute (and cherrypy.expose)
- * cherrypy.quickstart()
- * _cp_config attributes
- * cherrypy.tools (including cherrypy.session)
- * cherrypy.url()
-
-The ENVIRONMENT LAYER is used by developers at all levels. It provides
-information about the current request and response, plus the application
-and server environment, via a (default) set of top-level objects:
-
- * cherrypy.request
- * cherrypy.response
- * cherrypy.engine
- * cherrypy.server
- * cherrypy.tree
- * cherrypy.config
- * cherrypy.thread_data
- * cherrypy.log
- * cherrypy.HTTPError, NotFound, and HTTPRedirect
- * cherrypy.lib
-
-The EXTENSION LAYER allows advanced users to construct and share their own
-plugins. It consists of:
-
- * Hook API
- * Tool API
- * Toolbox API
- * Dispatch API
- * Config Namespace API
-
-Finally, there is the CORE LAYER, which uses the core API's to construct
-the default components which are available at higher layers. You can think
-of the default components as the 'reference implementation' for CherryPy.
-Megaframeworks (and advanced users) may replace the default components
-with customized or extended components. The core API's are:
-
- * Application API
- * Engine API
- * Request API
- * Server API
- * WSGI API
-
-These API's are described in the CherryPy specification:
-http://www.cherrypy.org/wiki/CherryPySpec
-"""
-
-__version__ = "3.2.0rc1"
-
-from urlparse import urljoin as _urljoin
-from urllib import urlencode as _urlencode
-
-
-class _AttributeDocstrings(type):
-    """Metaclass for declaring docstrings for class attributes."""
-    # The full docstring for this type is down in the __init__ method so
-    # that it doesn't show up in help() for every consumer class.
-    
-    def __init__(cls, name, bases, dct):
-        '''Metaclass for declaring docstrings for class attributes.
-        
-        Base Python doesn't provide any syntax for setting docstrings on
-        'data attributes' (non-callables). This metaclass allows class
-        definitions to follow the declaration of a data attribute with
-        a docstring for that attribute; the attribute docstring will be
-        popped from the class dict and folded into the class docstring.
-        
-        The naming convention for attribute docstrings is:
-            <attrname> + "__doc".
-        For example:
-        
-            class Thing(object):
-                """A thing and its properties."""
-                
-                __metaclass__ = cherrypy._AttributeDocstrings
-                
-                height = 50
-                height__doc = """The height of the Thing in inches."""
-        
-        In which case, help(Thing) starts like this:
-        
-            >>> help(mod.Thing)
-            Help on class Thing in module pkg.mod:
-            
-            class Thing(__builtin__.object)
-             |  A thing and its properties.
-             |  
-             |  height [= 50]:
-             |      The height of the Thing in inches.
-             | 
-        
-        The benefits of this approach over hand-edited class docstrings:
-            1. Places the docstring nearer to the attribute declaration.
-            2. Makes attribute docs more uniform ("name (default): doc").
-            3. Reduces mismatches of attribute _names_ between
-               the declaration and the documentation.
-            4. Reduces mismatches of attribute default _values_ between
-               the declaration and the documentation.
-        
-        The benefits of a metaclass approach over other approaches:
-            1. Simpler ("less magic") than interface-based solutions.
-            2. __metaclass__ can be specified at the module global level
-               for classic classes.
-        
-        For various formatting reasons, you should write multiline docs
-        with a leading newline and not a trailing one:
-            
-            response__doc = """
-            The response object for the current thread. In the main thread,
-            and any threads which are not HTTP requests, this is None."""
-        
-        The type of the attribute is intentionally not included, because
-        that's not How Python Works. Quack.
-        '''
-        
-        newdoc = [cls.__doc__ or ""]
-        
-        dctkeys = dct.keys()
-        dctkeys.sort()
-        for name in dctkeys:
-            if name.endswith("__doc"):
-                # Remove the magic doc attribute.
-                if hasattr(cls, name):
-                    delattr(cls, name)
-                
-                # Make a uniformly-indented docstring from it.
-                val = '\n'.join(['    ' + line.strip()
-                                 for line in dct[name].split('\n')])
-                
-                # Get the default value.
-                attrname = name[:-5]
-                try:
-                    attrval = getattr(cls, attrname)
-                except AttributeError:
-                    attrval = "missing"
-                
-                # Add the complete attribute docstring to our list.
-                newdoc.append("%s [= %r]:\n%s" % (attrname, attrval, val))
-        
-        # Add our list of new docstrings to the class docstring.
-        cls.__doc__ = "\n\n".join(newdoc)
-
-
-from cherrypy._cperror import HTTPError, HTTPRedirect, InternalRedirect
-from cherrypy._cperror import NotFound, CherryPyException, TimeoutError
-
-from cherrypy import _cpdispatch as dispatch
-
-from cherrypy import _cptools
-tools = _cptools.default_toolbox
-Tool = _cptools.Tool
-
-from cherrypy import _cprequest
-from cherrypy.lib import httputil as _httputil
-
-from cherrypy import _cptree
-tree = _cptree.Tree()
-from cherrypy._cptree import Application
-from cherrypy import _cpwsgi as wsgi
-
-from cherrypy import process
-try:
-    from cherrypy.process import win32
-    engine = win32.Win32Bus()
-    engine.console_control_handler = win32.ConsoleCtrlHandler(engine)
-    del win32
-except ImportError:
-    engine = process.bus
-
-
-# Timeout monitor
-class _TimeoutMonitor(process.plugins.Monitor):
-    
-    def __init__(self, bus):
-        self.servings = []
-        process.plugins.Monitor.__init__(self, bus, self.run)
-    
-    def acquire(self):
-        self.servings.append((serving.request, serving.response))
-    
-    def release(self):
-        try:
-            self.servings.remove((serving.request, serving.response))
-        except ValueError:
-            pass
-    
-    def run(self):
-        """Check timeout on all responses. (Internal)"""
-        for req, resp in self.servings:
-            resp.check_timeout()
-engine.timeout_monitor = _TimeoutMonitor(engine)
-engine.timeout_monitor.subscribe()
-
-engine.autoreload = process.plugins.Autoreloader(engine)
-engine.autoreload.subscribe()
-
-engine.thread_manager = process.plugins.ThreadManager(engine)
-engine.thread_manager.subscribe()
-
-engine.signal_handler = process.plugins.SignalHandler(engine)
-
-
-from cherrypy import _cpserver
-server = _cpserver.Server()
-server.subscribe()
-
-
-def quickstart(root=None, script_name="", config=None):
-    """Mount the given root, start the builtin server (and engine), then block.
-    
-    root: an instance of a "controller class" (a collection of page handler
-        methods) which represents the root of the application.
-    script_name: a string containing the "mount point" of the application.
-        This should start with a slash, and be the path portion of the URL
-        at which to mount the given root. For example, if root.index() will
-        handle requests to "http://www.example.com:8080/dept/app1/", then
-        the script_name argument would be "/dept/app1".
-        
-        It MUST NOT end in a slash. If the script_name refers to the root
-        of the URI, it MUST be an empty string (not "/").
-    config: a file or dict containing application config. If this contains
-        a [global] section, those entries will be used in the global
-        (site-wide) config.
-    """
-    if config:
-        _global_conf_alias.update(config)
-    
-    tree.mount(root, script_name, config)
-    
-    if hasattr(engine, "signal_handler"):
-        engine.signal_handler.subscribe()
-    if hasattr(engine, "console_control_handler"):
-        engine.console_control_handler.subscribe()
-    
-    engine.start()
-    engine.block()
-
-
-try:
-    from threading import local as _local
-except ImportError:
-    from cherrypy._cpthreadinglocal import local as _local
-
-class _Serving(_local):
-    """An interface for registering request and response objects.
-    
-    Rather than have a separate "thread local" object for the request and
-    the response, this class works as a single threadlocal container for
-    both objects (and any others which developers wish to define). In this
-    way, we can easily dump those objects when we stop/start a new HTTP
-    conversation, yet still refer to them as module-level globals in a
-    thread-safe way.
-    """
-    
-    __metaclass__ = _AttributeDocstrings
-    
-    request = _cprequest.Request(_httputil.Host("127.0.0.1", 80),
-                                 _httputil.Host("127.0.0.1", 1111))
-    request__doc = """
-    The request object for the current thread. In the main thread,
-    and any threads which are not receiving HTTP requests, this is None."""
-    
-    response = _cprequest.Response()
-    response__doc = """
-    The response object for the current thread. In the main thread,
-    and any threads which are not receiving HTTP requests, this is None."""
-    
-    def load(self, request, response):
-        self.request = request
-        self.response = response
-    
-    def clear(self):
-        """Remove all attributes of self."""
-        self.__dict__.clear()
-
-serving = _Serving()
-
-
-class _ThreadLocalProxy(object):
-    
-    __slots__ = ['__attrname__', '__dict__']
-    
-    def __init__(self, attrname):
-        self.__attrname__ = attrname
-    
-    def __getattr__(self, name):
-        child = getattr(serving, self.__attrname__)
-        return getattr(child, name)
-    
-    def __setattr__(self, name, value):
-        if name in ("__attrname__", ):
-            object.__setattr__(self, name, value)
-        else:
-            child = getattr(serving, self.__attrname__)
-            setattr(child, name, value)
-    
-    def __delattr__(self, name):
-        child = getattr(serving, self.__attrname__)
-        delattr(child, name)
-    
-    def _get_dict(self):
-        child = getattr(serving, self.__attrname__)
-        d = child.__class__.__dict__.copy()
-        d.update(child.__dict__)
-        return d
-    __dict__ = property(_get_dict)
-    
-    def __getitem__(self, key):
-        child = getattr(serving, self.__attrname__)
-        return child[key]
-    
-    def __setitem__(self, key, value):
-        child = getattr(serving, self.__attrname__)
-        child[key] = value
-    
-    def __delitem__(self, key):
-        child = getattr(serving, self.__attrname__)
-        del child[key]
-    
-    def __contains__(self, key):
-        child = getattr(serving, self.__attrname__)
-        return key in child
-    
-    def __len__(self):
-        child = getattr(serving, self.__attrname__)
-        return len(child)
-    
-    def __nonzero__(self):
-        child = getattr(serving, self.__attrname__)
-        return bool(child)
-
-
-# Create request and response object (the same objects will be used
-#   throughout the entire life of the webserver, but will redirect
-#   to the "serving" object)
-request = _ThreadLocalProxy('request')
-response = _ThreadLocalProxy('response')
-
-# Create thread_data object as a thread-specific all-purpose storage
-class _ThreadData(_local):
-    """A container for thread-specific data."""
-thread_data = _ThreadData()
-
-
-# Monkeypatch pydoc to allow help() to go through the threadlocal proxy.
-# Jan 2007: no Googleable examples of anyone else replacing pydoc.resolve.
-# The only other way would be to change what is returned from type(request)
-# and that's not possible in pure Python (you'd have to fake ob_type).
-def _cherrypy_pydoc_resolve(thing, forceload=0):
-    """Given an object or a path to an object, get the object and its name."""
-    if isinstance(thing, _ThreadLocalProxy):
-        thing = getattr(serving, thing.__attrname__)
-    return _pydoc._builtin_resolve(thing, forceload)
-
-try:
-    import pydoc as _pydoc
-    _pydoc._builtin_resolve = _pydoc.resolve
-    _pydoc.resolve = _cherrypy_pydoc_resolve
-except ImportError:
-    pass
-
-
-from cherrypy import _cplogging
-
-class _GlobalLogManager(_cplogging.LogManager):
-    
-    def __call__(self, *args, **kwargs):
-        # Do NOT use try/except here. See http://www.cherrypy.org/ticket/945
-        if hasattr(request, 'app') and hasattr(request.app, 'log'):
-            log = request.app.log
-        else:
-            log = self
-        return log.error(*args, **kwargs)
-    
-    def access(self):
-        try:
-            return request.app.log.access()
-        except AttributeError:
-            return _cplogging.LogManager.access(self)
-
-
-log = _GlobalLogManager()
-# Set a default screen handler on the global log.
-log.screen = True
-log.error_file = ''
-# Using an access file makes CP about 10% slower. Leave off by default.
-log.access_file = ''
-
-def _buslog(msg, level):
-    log.error(msg, 'ENGINE', severity=level)
-engine.subscribe('log', _buslog)
-
-#                       Helper functions for CP apps                       #
-
-
-def expose(func=None, alias=None):
-    """Expose the function, optionally providing an alias or set of aliases."""
-    def expose_(func):
-        func.exposed = True
-        if alias is not None:
-            if isinstance(alias, basestring):
-                parents[alias.replace(".", "_")] = func
-            else:
-                for a in alias:
-                    parents[a.replace(".", "_")] = func
-        return func
-    
-    import sys, types
-    if isinstance(func, (types.FunctionType, types.MethodType)):
-        if alias is None:
-            # @expose
-            func.exposed = True
-            return func
-        else:
-            # func = expose(func, alias)
-            parents = sys._getframe(1).f_locals
-            return expose_(func)
-    elif func is None:
-        if alias is None:
-            # @expose()
-            parents = sys._getframe(1).f_locals
-            return expose_
-        else:
-            # @expose(alias="alias") or
-            # @expose(alias=["alias1", "alias2"])
-            parents = sys._getframe(1).f_locals
-            return expose_
-    else:
-        # @expose("alias") or
-        # @expose(["alias1", "alias2"])
-        parents = sys._getframe(1).f_locals
-        alias = func
-        return expose_
-
-
-def url(path="", qs="", script_name=None, base=None, relative=None):
-    """Create an absolute URL for the given path.
-    
-    If 'path' starts with a slash ('/'), this will return
-        (base + script_name + path + qs).
-    If it does not start with a slash, this returns
-        (base + script_name [+ request.path_info] + path + qs).
-    
-    If script_name is None, cherrypy.request will be used
-    to find a script_name, if available.
-    
-    If base is None, cherrypy.request.base will be used (if available).
-    Note that you can use cherrypy.tools.proxy to change this.
-    
-    Finally, note that this function can be used to obtain an absolute URL
-    for the current request path (minus the querystring) by passing no args.
-    If you call url(qs=cherrypy.request.query_string), you should get the
-    original browser URL (assuming no internal redirections).
-    
-    If relative is None or not provided, request.app.relative_urls will
-    be used (if available, else False). If False, the output will be an
-    absolute URL (including the scheme, host, vhost, and script_name).
-    If True, the output will instead be a URL that is relative to the
-    current request path, perhaps including '..' atoms. If relative is
-    the string 'server', the output will instead be a URL that is
-    relative to the server root; i.e., it will start with a slash.
-    """
-    if isinstance(qs, (tuple, list, dict)):
-        qs = _urlencode(qs)
-    if qs:
-        qs = '?' + qs
-    
-    if request.app:
-        if not path.startswith("/"):
-            # Append/remove trailing slash from path_info as needed
-            # (this is to support mistyped URL's without redirecting;
-            # if you want to redirect, use tools.trailing_slash).
-            pi = request.path_info
-            if request.is_index is True:
-                if not pi.endswith('/'):
-                    pi = pi + '/'
-            elif request.is_index is False:
-                if pi.endswith('/') and pi != '/':
-                    pi = pi[:-1]
-            
-            if path == "":
-                path = pi
-            else:
-                path = _urljoin(pi, path)
-        
-        if script_name is None:
-            script_name = request.script_name
-        if base is None:
-            base = request.base
-        
-        newurl = base + script_name + path + qs
-    else:
-        # No request.app (we're being called outside a request).
-        # We'll have to guess the base from server.* attributes.
-        # This will produce very different results from the above
-        # if you're using vhosts or tools.proxy.
-        if base is None:
-            base = server.base()
-        
-        path = (script_name or "") + path
-        newurl = base + path + qs
-    
-    if './' in newurl:
-        # Normalize the URL by removing ./ and ../
-        atoms = []
-        for atom in newurl.split('/'):
-            if atom == '.':
-                pass
-            elif atom == '..':
-                atoms.pop()
-            else:
-                atoms.append(atom)
-        newurl = '/'.join(atoms)
-    
-    # At this point, we should have a fully-qualified absolute URL.
-    
-    if relative is None:
-        relative = getattr(request.app, "relative_urls", False)
-    
-    # See http://www.ietf.org/rfc/rfc2396.txt
-    if relative == 'server':
-        # "A relative reference beginning with a single slash character is
-        # termed an absolute-path reference, as defined by <abs_path>..."
-        # This is also sometimes called "server-relative".
-        newurl = '/' + '/'.join(newurl.split('/', 3)[3:])
-    elif relative:
-        # "A relative reference that does not begin with a scheme name
-        # or a slash character is termed a relative-path reference."
-        old = url().split('/')[:-1]
-        new = newurl.split('/')
-        while old and new:
-            a, b = old[0], new[0]
-            if a != b:
-                break
-            old.pop(0)
-            new.pop(0)
-        new = (['..'] * len(old)) + new
-        newurl = '/'.join(new)
-    
-    return newurl
-
-
-# import _cpconfig last so it can reference other top-level objects
-from cherrypy import _cpconfig
-# Use _global_conf_alias so quickstart can use 'config' as an arg
-# without shadowing cherrypy.config.
-config = _global_conf_alias = _cpconfig.Config()
-config.defaults = {
-    'tools.log_tracebacks.on': True,
-    'tools.log_headers.on': True,
-    'tools.trailing_slash.on': True,
-    'tools.encode.on': True
-    }
-config.namespaces["log"] = lambda k, v: setattr(log, k, v)
-config.namespaces["checker"] = lambda k, v: setattr(checker, k, v)
-# Must reset to get our defaults applied.
-config.reset()
-
-from cherrypy import _cpchecker
-checker = _cpchecker.Checker()
-engine.subscribe('start', checker)
--- a/bundled/cherrypy/cherrypy/_cpchecker.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,322 +0,0 @@
-import os
-import warnings
-
-import cherrypy
-
-
-class Checker(object):
-    """A checker for CherryPy sites and their mounted applications.
-    
-    on: set this to False to turn off the checker completely.
-    
-    When this object is called at engine startup, it executes each
-    of its own methods whose names start with "check_". If you wish
-    to disable selected checks, simply add a line in your global
-    config which sets the appropriate method to False:
-    
-    [global]
-    checker.check_skipped_app_config = False
-    
-    You may also dynamically add or replace check_* methods in this way.
-    """
-    
-    on = True
-    
-    def __init__(self):
-        self._populate_known_types()
-    
-    def __call__(self):
-        """Run all check_* methods."""
-        if self.on:
-            oldformatwarning = warnings.formatwarning
-            warnings.formatwarning = self.formatwarning
-            try:
-                for name in dir(self):
-                    if name.startswith("check_"):
-                        method = getattr(self, name)
-                        if method and callable(method):
-                            method()
-            finally:
-                warnings.formatwarning = oldformatwarning
-    
-    def formatwarning(self, message, category, filename, lineno, line=None):
-        """Function to format a warning."""
-        return "CherryPy Checker:\n%s\n\n" % message
-    
-    # This value should be set inside _cpconfig.
-    global_config_contained_paths = False
-    
-    def check_app_config_entries_dont_start_with_script_name(self):
-        for sn, app in cherrypy.tree.apps.items():
-            if not isinstance(app, cherrypy.Application):
-                continue
-            if not app.config:
-                continue
-            if sn == '':
-                continue
-            sn_atoms = sn.strip("/").split("/")
-            for key in app.config.keys():
-                key_atoms = key.strip("/").split("/")
-                if key_atoms[:len(sn_atoms)] == sn_atoms:
-                    warnings.warn(
-                        "The application mounted at %r has config " \
-                        "entries that start with its script name: %r" % (sn, key))
-    
-    def check_site_config_entries_in_app_config(self):
-        for sn, app in cherrypy.tree.apps.iteritems():
-            if not isinstance(app, cherrypy.Application):
-                continue
-            
-            msg = []
-            for section, entries in app.config.iteritems():
-                if section.startswith('/'):
-                    for key, value in entries.iteritems():
-                        for n in ("engine.", "server.", "tree.", "checker."):
-                            if key.startswith(n):
-                                msg.append("[%s] %s = %s" % (section, key, value))
-            if msg:
-                msg.insert(0,
-                    "The application mounted at %r contains the following "
-                    "config entries, which are only allowed in site-wide "
-                    "config. Move them to a [global] section and pass them "
-                    "to cherrypy.config.update() instead of tree.mount()." % sn)
-                warnings.warn(os.linesep.join(msg))
-    
-    def check_skipped_app_config(self):
-        for sn, app in cherrypy.tree.apps.items():
-            if not isinstance(app, cherrypy.Application):
-                continue
-            if not app.config:
-                msg = "The Application mounted at %r has an empty config." % sn
-                if self.global_config_contained_paths:
-                    msg += (" It looks like the config you passed to "
-                            "cherrypy.config.update() contains application-"
-                            "specific sections. You must explicitly pass "
-                            "application config via "
-                            "cherrypy.tree.mount(..., config=app_config)")
-                warnings.warn(msg)
-                return
-    
-    def check_app_config_brackets(self):
-        for sn, app in cherrypy.tree.apps.items():
-            if not isinstance(app, cherrypy.Application):
-                continue
-            if not app.config:
-                continue
-            for key in app.config.keys():
-                if key.startswith("[") or key.endswith("]"):
-                    warnings.warn(
-                        "The application mounted at %r has config " \
-                        "section names with extraneous brackets: %r. "
-                        "Config *files* need brackets; config *dicts* "
-                        "(e.g. passed to tree.mount) do not." % (sn, key))
-    
-    def check_static_paths(self):
-        # Use the dummy Request object in the main thread.
-        request = cherrypy.request
-        for sn, app in cherrypy.tree.apps.items():
-            if not isinstance(app, cherrypy.Application):
-                continue
-            request.app = app
-            for section in app.config:
-                # get_resource will populate request.config
-                request.get_resource(section + "/dummy.html")
-                conf = request.config.get
-                
-                if conf("tools.staticdir.on", False):
-                    msg = ""
-                    root = conf("tools.staticdir.root")
-                    dir = conf("tools.staticdir.dir")
-                    if dir is None:
-                        msg = "tools.staticdir.dir is not set."
-                    else:
-                        fulldir = ""
-                        if os.path.isabs(dir):
-                            fulldir = dir
-                            if root:
-                                msg = ("dir is an absolute path, even "
-                                       "though a root is provided.")
-                                testdir = os.path.join(root, dir[1:])
-                                if os.path.exists(testdir):
-                                    msg += ("\nIf you meant to serve the "
-                                            "filesystem folder at %r, remove "
-                                            "the leading slash from dir." % testdir)
-                        else:
-                            if not root:
-                                msg = "dir is a relative path and no root provided."
-                            else:
-                                fulldir = os.path.join(root, dir)
-                                if not os.path.isabs(fulldir):
-                                    msg = "%r is not an absolute path." % fulldir
-                        
-                        if fulldir and not os.path.exists(fulldir):
-                            if msg:
-                                msg += "\n"
-                            msg += ("%r (root + dir) is not an existing "
-                                    "filesystem path." % fulldir)
-                    
-                    if msg:
-                        warnings.warn("%s\nsection: [%s]\nroot: %r\ndir: %r"
-                                      % (msg, section, root, dir))
-    
-    
-    # -------------------------- Compatibility -------------------------- #
-    
-    obsolete = {
-        'server.default_content_type': 'tools.response_headers.headers',
-        'log_access_file': 'log.access_file',
-        'log_config_options': None,
-        'log_file': 'log.error_file',
-        'log_file_not_found': None,
-        'log_request_headers': 'tools.log_headers.on',
-        'log_to_screen': 'log.screen',
-        'show_tracebacks': 'request.show_tracebacks',
-        'throw_errors': 'request.throw_errors',
-        'profiler.on': ('cherrypy.tree.mount(profiler.make_app('
-                        'cherrypy.Application(Root())))'),
-        }
-    
-    deprecated = {}
-    
-    def _compat(self, config):
-        """Process config and warn on each obsolete or deprecated entry."""
-        for section, conf in config.items():
-            if isinstance(conf, dict):
-                for k, v in conf.items():
-                    if k in self.obsolete:
-                        warnings.warn("%r is obsolete. Use %r instead.\n"
-                                      "section: [%s]" %
-                                      (k, self.obsolete[k], section))
-                    elif k in self.deprecated:
-                        warnings.warn("%r is deprecated. Use %r instead.\n"
-                                      "section: [%s]" %
-                                      (k, self.deprecated[k], section))
-            else:
-                if section in self.obsolete:
-                    warnings.warn("%r is obsolete. Use %r instead."
-                                  % (section, self.obsolete[section]))
-                elif section in self.deprecated:
-                    warnings.warn("%r is deprecated. Use %r instead."
-                                  % (section, self.deprecated[section]))
-    
-    def check_compatibility(self):
-        """Process config and warn on each obsolete or deprecated entry."""
-        self._compat(cherrypy.config)
-        for sn, app in cherrypy.tree.apps.items():
-            if not isinstance(app, cherrypy.Application):
-                continue
-            self._compat(app.config)
-    
-    
-    # ------------------------ Known Namespaces ------------------------ #
-    
-    extra_config_namespaces = []
-    
-    def _known_ns(self, app):
-        ns = ["wsgi"]
-        ns.extend(app.toolboxes.keys())
-        ns.extend(app.namespaces.keys())
-        ns.extend(app.request_class.namespaces.keys())
-        ns.extend(cherrypy.config.namespaces.keys())
-        ns += self.extra_config_namespaces
-        
-        for section, conf in app.config.items():
-            is_path_section = section.startswith("/")
-            if is_path_section and isinstance(conf, dict):
-                for k, v in conf.items():
-                    atoms = k.split(".")
-                    if len(atoms) > 1:
-                        if atoms[0] not in ns:
-                            # Spit out a special warning if a known
-                            # namespace is preceded by "cherrypy."
-                            if (atoms[0] == "cherrypy" and atoms[1] in ns):
-                                msg = ("The config entry %r is invalid; "
-                                       "try %r instead.\nsection: [%s]"
-                                       % (k, ".".join(atoms[1:]), section))
-                            else:
-                                msg = ("The config entry %r is invalid, because "
-                                       "the %r config namespace is unknown.\n"
-                                       "section: [%s]" % (k, atoms[0], section))
-                            warnings.warn(msg)
-                        elif atoms[0] == "tools":
-                            if atoms[1] not in dir(cherrypy.tools):
-                                msg = ("The config entry %r may be invalid, "
-                                       "because the %r tool was not found.\n"
-                                       "section: [%s]" % (k, atoms[1], section))
-                                warnings.warn(msg)
-    
-    def check_config_namespaces(self):
-        """Process config and warn on each unknown config namespace."""
-        for sn, app in cherrypy.tree.apps.items():
-            if not isinstance(app, cherrypy.Application):
-                continue
-            self._known_ns(app)
-
-
-    
-    
-    # -------------------------- Config Types -------------------------- #
-    
-    known_config_types = {}
-    
-    def _populate_known_types(self):
-        import __builtin__ as builtins
-        b = [x for x in vars(builtins).values()
-             if type(x) is type(str)]
-        
-        def traverse(obj, namespace):
-            for name in dir(obj):
-                # Hack for 3.2's warning about body_params
-                if name == 'body_params':
-                    continue
-                vtype = type(getattr(obj, name, None))
-                if vtype in b:
-                    self.known_config_types[namespace + "." + name] = vtype
-        
-        traverse(cherrypy.request, "request")
-        traverse(cherrypy.response, "response")
-        traverse(cherrypy.server, "server")
-        traverse(cherrypy.engine, "engine")
-        traverse(cherrypy.log, "log")
-    
-    def _known_types(self, config):
-        msg = ("The config entry %r in section %r is of type %r, "
-               "which does not match the expected type %r.")
-        
-        for section, conf in config.items():
-            if isinstance(conf, dict):
-                for k, v in conf.items():
-                    if v is not None:
-                        expected_type = self.known_config_types.get(k, None)
-                        vtype = type(v)
-                        if expected_type and vtype != expected_type:
-                            warnings.warn(msg % (k, section, vtype.__name__,
-                                                 expected_type.__name__))
-            else:
-                k, v = section, conf
-                if v is not None:
-                    expected_type = self.known_config_types.get(k, None)
-                    vtype = type(v)
-                    if expected_type and vtype != expected_type:
-                        warnings.warn(msg % (k, section, vtype.__name__,
-                                             expected_type.__name__))
-    
-    def check_config_types(self):
-        """Assert that config values are of the same type as default values."""
-        self._known_types(cherrypy.config)
-        for sn, app in cherrypy.tree.apps.items():
-            if not isinstance(app, cherrypy.Application):
-                continue
-            self._known_types(app.config)
-    
-    
-    # -------------------- Specific config warnings -------------------- #
-    
-    def check_localhost(self):
-        """Warn if any socket_host is 'localhost'. See #711."""
-        for k, v in cherrypy.config.items():
-            if k == 'server.socket_host' and v == 'localhost':
-                warnings.warn("The use of 'localhost' as a socket host can "
-                    "cause problems on newer systems, since 'localhost' can "
-                    "map to either an IPv4 or an IPv6 address. You should "
-                    "use '127.0.0.1' or '[::1]' instead.")
--- a/bundled/cherrypy/cherrypy/_cpconfig.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,269 +0,0 @@
-"""Configuration system for CherryPy.
-
-Configuration in CherryPy is implemented via dictionaries. Keys are strings
-which name the mapped value, which may be of any type.
-
-
-Architecture
-------------
-
-CherryPy Requests are part of an Application, which runs in a global context,
-and configuration data may apply to any of those three scopes:
-
-    Global: configuration entries which apply everywhere are stored in
-    cherrypy.config.
-    
-    Application: entries which apply to each mounted application are stored
-    on the Application object itself, as 'app.config'. This is a two-level
-    dict where each key is a path, or "relative URL" (for example, "/" or
-    "/path/to/my/page"), and each value is a config dict. Usually, this
-    data is provided in the call to tree.mount(root(), config=conf),
-    although you may also use app.merge(conf).
-    
-    Request: each Request object possesses a single 'Request.config' dict.
-    Early in the request process, this dict is populated by merging global
-    config entries, Application entries (whose path equals or is a parent
-    of Request.path_info), and any config acquired while looking up the
-    page handler (see next).
-
-
-Declaration
------------
-
-Configuration data may be supplied as a Python dictionary, as a filename,
-or as an open file object. When you supply a filename or file, CherryPy
-uses Python's builtin ConfigParser; you declare Application config by
-writing each path as a section header:
-
-    [/path/to/my/page]
-    request.stream = True
-
-To declare global configuration entries, place them in a [global] section.
-
-You may also declare config entries directly on the classes and methods
-(page handlers) that make up your CherryPy application via the '_cp_config'
-attribute. For example:
-
-    class Demo:
-        _cp_config = {'tools.gzip.on': True}
-        
-        def index(self):
-            return "Hello world"
-        index.exposed = True
-        index._cp_config = {'request.show_tracebacks': False}
-
-Note, however, that this behavior is only guaranteed for the default
-dispatcher. Other dispatchers may have different restrictions on where
-you can attach _cp_config attributes.
-
-
-Namespaces
-----------
-
-Configuration keys are separated into namespaces by the first "." in the key.
-Current namespaces:
-
-    engine:     Controls the 'application engine', including autoreload.
-                These can only be declared in the global config.
-    tree:       Grafts cherrypy.Application objects onto cherrypy.tree.
-                These can only be declared in the global config.
-    hooks:      Declares additional request-processing functions.
-    log:        Configures the logging for each application.
-                These can only be declared in the global or / config.
-    request:    Adds attributes to each Request.
-    response:   Adds attributes to each Response.
-    server:     Controls the default HTTP server via cherrypy.server.
-                These can only be declared in the global config.
-    tools:      Runs and configures additional request-processing packages.
-    wsgi:       Adds WSGI middleware to an Application's "pipeline".
-                These can only be declared in the app's root config ("/").
-    checker:    Controls the 'checker', which looks for common errors in
-                app state (including config) when the engine starts.
-                Global config only.
-
-The only key that does not exist in a namespace is the "environment" entry.
-This special entry 'imports' other config entries from a template stored in
-cherrypy._cpconfig.environments[environment]. It only applies to the global
-config, and only when you use cherrypy.config.update.
-
-You can define your own namespaces to be called at the Global, Application,
-or Request level, by adding a named handler to cherrypy.config.namespaces,
-app.namespaces, or app.request_class.namespaces. The name can
-be any string, and the handler must be either a callable or a (Python 2.5
-style) context manager.
-"""
-
-try:
-    set
-except NameError:
-    from sets import Set as set
-
-import cherrypy
-from cherrypy.lib import reprconf
-
-# Deprecated in  CherryPy 3.2--remove in 3.3
-NamespaceSet = reprconf.NamespaceSet
-
-def merge(base, other):
-    """Merge one app config (from a dict, file, or filename) into another.
-    
-    If the given config is a filename, it will be appended to
-    the list of files to monitor for "autoreload" changes.
-    """
-    if isinstance(other, basestring):
-        cherrypy.engine.autoreload.files.add(other)
-    
-    # Load other into base
-    for section, value_map in reprconf.as_dict(other).items():
-        if not isinstance(value_map, dict):
-            raise ValueError(
-                "Application config must include section headers, but the "
-                "config you tried to merge doesn't have any sections. "
-                "Wrap your config in another dict with paths as section "
-                "headers, for example: {'/': config}.")
-        base.setdefault(section, {}).update(value_map)
-
-
-class Config(reprconf.Config):
-    """The 'global' configuration data for the entire CherryPy process."""
-
-    def update(self, config):
-        """Update self from a dict, file or filename."""
-        if isinstance(config, basestring):
-            # Filename
-            cherrypy.engine.autoreload.files.add(config)
-        reprconf.Config.update(self, config)
-
-    def _apply(self, config):
-        """Update self from a dict."""
-        if isinstance(config.get("global", None), dict):
-            if len(config) > 1:
-                cherrypy.checker.global_config_contained_paths = True
-            config = config["global"]
-        if 'tools.staticdir.dir' in config:
-            config['tools.staticdir.section'] = "global"
-        reprconf.Config._apply(self, config)
-    
-    def __call__(self, *args, **kwargs):
-        """Decorator for page handlers to set _cp_config."""
-        if args:
-            raise TypeError(
-                "The cherrypy.config decorator does not accept positional "
-                "arguments; you must use keyword arguments.")
-        def tool_decorator(f):
-            if not hasattr(f, "_cp_config"):
-                f._cp_config = {}
-            for k, v in kwargs.items():
-                f._cp_config[k] = v
-            return f
-        return tool_decorator
-
-
-Config.environments = environments = {
-    "staging": {
-        'engine.autoreload_on': False,
-        'checker.on': False,
-        'tools.log_headers.on': False,
-        'request.show_tracebacks': False,
-        'request.show_mismatched_params': False,
-        },
-    "production": {
-        'engine.autoreload_on': False,
-        'checker.on': False,
-        'tools.log_headers.on': False,
-        'request.show_tracebacks': False,
-        'request.show_mismatched_params': False,
-        'log.screen': False,
-        },
-    "embedded": {
-        # For use with CherryPy embedded in another deployment stack.
-        'engine.autoreload_on': False,
-        'checker.on': False,
-        'tools.log_headers.on': False,
-        'request.show_tracebacks': False,
-        'request.show_mismatched_params': False,
-        'log.screen': False,
-        'engine.SIGHUP': None,
-        'engine.SIGTERM': None,
-        },
-    "test_suite": {
-        'engine.autoreload_on': False,
-        'checker.on': False,
-        'tools.log_headers.on': False,
-        'request.show_tracebacks': True,
-        'request.show_mismatched_params': True,
-        'log.screen': False,
-        },
-    }
-
-
-def _server_namespace_handler(k, v):
-    """Config handler for the "server" namespace."""
-    atoms = k.split(".", 1)
-    if len(atoms) > 1:
-        # Special-case config keys of the form 'server.servername.socket_port'
-        # to configure additional HTTP servers.
-        if not hasattr(cherrypy, "servers"):
-            cherrypy.servers = {}
-        
-        servername, k = atoms
-        if servername not in cherrypy.servers:
-            from cherrypy import _cpserver
-            cherrypy.servers[servername] = _cpserver.Server()
-            # On by default, but 'on = False' can unsubscribe it (see below).
-            cherrypy.servers[servername].subscribe()
-        
-        if k == 'on':
-            if v:
-                cherrypy.servers[servername].subscribe()
-            else:
-                cherrypy.servers[servername].unsubscribe()
-        else:
-            setattr(cherrypy.servers[servername], k, v)
-    else:
-        setattr(cherrypy.server, k, v)
-Config.namespaces["server"] = _server_namespace_handler
-
-def _engine_namespace_handler(k, v):
-    """Backward compatibility handler for the "engine" namespace."""
-    engine = cherrypy.engine
-    if k == 'autoreload_on':
-        if v:
-            engine.autoreload.subscribe()
-        else:
-            engine.autoreload.unsubscribe()
-    elif k == 'autoreload_frequency':
-        engine.autoreload.frequency = v
-    elif k == 'autoreload_match':
-        engine.autoreload.match = v
-    elif k == 'reload_files':
-        engine.autoreload.files = set(v)
-    elif k == 'deadlock_poll_freq':
-        engine.timeout_monitor.frequency = v
-    elif k == 'SIGHUP':
-        engine.listeners['SIGHUP'] = set([v])
-    elif k == 'SIGTERM':
-        engine.listeners['SIGTERM'] = set([v])
-    elif "." in k:
-        plugin, attrname = k.split(".", 1)
-        plugin = getattr(engine, plugin)
-        if attrname == 'on':
-            if v and hasattr(getattr(plugin, 'subscribe', None), '__call__'):
-                plugin.subscribe()
-                return
-            elif (not v) and hasattr(getattr(plugin, 'unsubscribe', None), '__call__'):
-                plugin.unsubscribe()
-                return
-        setattr(plugin, attrname, v)
-    else:
-        setattr(engine, k, v)
-Config.namespaces["engine"] = _engine_namespace_handler
-
-
-def _tree_namespace_handler(k, v):
-    """Namespace handler for the 'tree' config namespace."""
-    cherrypy.tree.graft(v, v.script_name)
-    cherrypy.engine.log("Mounted: %s on %s" % (v, v.script_name or "/"))
-Config.namespaces["tree"] = _tree_namespace_handler
-
-
--- a/bundled/cherrypy/cherrypy/_cpdispatch.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,568 +0,0 @@
-"""CherryPy dispatchers.
-
-A 'dispatcher' is the object which looks up the 'page handler' callable
-and collects config for the current request based on the path_info, other
-request attributes, and the application architecture. The core calls the
-dispatcher as early as possible, passing it a 'path_info' argument.
-
-The default dispatcher discovers the page handler by matching path_info
-to a hierarchical arrangement of objects, starting at request.app.root.
-"""
-
-import cherrypy
-
-
-class PageHandler(object):
-    """Callable which sets response.body."""
-    
-    def __init__(self, callable, *args, **kwargs):
-        self.callable = callable
-        self.args = args
-        self.kwargs = kwargs
-    
-    def __call__(self):
-        try:
-            return self.callable(*self.args, **self.kwargs)
-        except TypeError, x:
-            try:
-                test_callable_spec(self.callable, self.args, self.kwargs)
-            except cherrypy.HTTPError, error:
-                raise error
-            except:
-                raise x
-            raise
-
-
-def test_callable_spec(callable, callable_args, callable_kwargs):
-    """
-    Inspect callable and test to see if the given args are suitable for it.
-
-    When an error occurs during the handler's invoking stage there are 2
-    erroneous cases:
-    1.  Too many parameters passed to a function which doesn't define
-        one of *args or **kwargs.
-    2.  Too little parameters are passed to the function.
-
-    There are 3 sources of parameters to a cherrypy handler.
-    1.  query string parameters are passed as keyword parameters to the handler.
-    2.  body parameters are also passed as keyword parameters.
-    3.  when partial matching occurs, the final path atoms are passed as
-        positional args.
-    Both the query string and path atoms are part of the URI.  If they are
-    incorrect, then a 404 Not Found should be raised. Conversely the body
-    parameters are part of the request; if they are invalid a 400 Bad Request.
-    """
-    show_mismatched_params = getattr(
-        cherrypy.serving.request, 'show_mismatched_params', False)
-    try:
-        (args, varargs, varkw, defaults) = inspect.getargspec(callable)
-    except TypeError:
-        if isinstance(callable, object) and hasattr(callable, '__call__'):
-            (args, varargs, varkw, defaults) = inspect.getargspec(callable.__call__)
-        else:
-            # If it wasn't one of our own types, re-raise 
-            # the original error
-            raise
-
-    if args and args[0] == 'self':
-        args = args[1:]
-
-    arg_usage = dict([(arg, 0,) for arg in args])
-    vararg_usage = 0
-    varkw_usage = 0
-    extra_kwargs = set()
-
-    for i, value in enumerate(callable_args):
-        try:
-            arg_usage[args[i]] += 1
-        except IndexError:
-            vararg_usage += 1
-
-    for key in callable_kwargs.keys():
-        try:
-            arg_usage[key] += 1
-        except KeyError:
-            varkw_usage += 1
-            extra_kwargs.add(key)
-
-    # figure out which args have defaults.
-    args_with_defaults = args[-len(defaults or []):]
-    for i, val in enumerate(defaults or []):
-        # Defaults take effect only when the arg hasn't been used yet.
-        if arg_usage[args_with_defaults[i]] == 0:
-            arg_usage[args_with_defaults[i]] += 1
-
-    missing_args = []
-    multiple_args = []
-    for key, usage in arg_usage.items():
-        if usage == 0:
-            missing_args.append(key)
-        elif usage > 1:
-            multiple_args.append(key)
-
-    if missing_args:
-        # In the case where the method allows body arguments
-        # there are 3 potential errors:
-        # 1. not enough query string parameters -> 404
-        # 2. not enough body parameters -> 400
-        # 3. not enough path parts (partial matches) -> 404
-        #
-        # We can't actually tell which case it is, 
-        # so I'm raising a 404 because that covers 2/3 of the
-        # possibilities
-        # 
-        # In the case where the method does not allow body
-        # arguments it's definitely a 404.
-        message = None
-        if show_mismatched_params:
-            message="Missing parameters: %s" % ",".join(missing_args)
-        raise cherrypy.HTTPError(404, message=message)
-
-    # the extra positional arguments come from the path - 404 Not Found
-    if not varargs and vararg_usage > 0:
-        raise cherrypy.HTTPError(404)
-
-    body_params = cherrypy.serving.request.body.params or {}
-    body_params = set(body_params.keys())
-    qs_params = set(callable_kwargs.keys()) - body_params
-
-    if multiple_args:
-        if qs_params.intersection(set(multiple_args)):
-            # If any of the multiple parameters came from the query string then
-            # it's a 404 Not Found
-            error = 404
-        else:
-            # Otherwise it's a 400 Bad Request
-            error = 400
-
-        message = None
-        if show_mismatched_params:
-            message="Multiple values for parameters: "\
-                    "%s" % ",".join(multiple_args)
-        raise cherrypy.HTTPError(error, message=message)
-
-    if not varkw and varkw_usage > 0:
-
-        # If there were extra query string parameters, it's a 404 Not Found
-        extra_qs_params = set(qs_params).intersection(extra_kwargs)
-        if extra_qs_params:
-            message = None
-            if show_mismatched_params:
-                message="Unexpected query string "\
-                        "parameters: %s" % ", ".join(extra_qs_params)
-            raise cherrypy.HTTPError(404, message=message)
-
-        # If there were any extra body parameters, it's a 400 Not Found
-        extra_body_params = set(body_params).intersection(extra_kwargs)
-        if extra_body_params:
-            message = None
-            if show_mismatched_params:
-                message="Unexpected body parameters: "\
-                        "%s" % ", ".join(extra_body_params)
-            raise cherrypy.HTTPError(400, message=message)
-
-
-try:
-    import inspect
-except ImportError:
-    test_callable_spec = lambda callable, args, kwargs: None
-
-
-
-class LateParamPageHandler(PageHandler):
-    """When passing cherrypy.request.params to the page handler, we do not
-    want to capture that dict too early; we want to give tools like the
-    decoding tool a chance to modify the params dict in-between the lookup
-    of the handler and the actual calling of the handler. This subclass
-    takes that into account, and allows request.params to be 'bound late'
-    (it's more complicated than that, but that's the effect).
-    """
-    
-    def _get_kwargs(self):
-        kwargs = cherrypy.serving.request.params.copy()
-        if self._kwargs:
-            kwargs.update(self._kwargs)
-        return kwargs
-    
-    def _set_kwargs(self, kwargs):
-        self._kwargs = kwargs
-    
-    kwargs = property(_get_kwargs, _set_kwargs,
-                      doc='page handler kwargs (with '
-                      'cherrypy.request.params copied in)')
-
-
-class Dispatcher(object):
-    """CherryPy Dispatcher which walks a tree of objects to find a handler.
-    
-    The tree is rooted at cherrypy.request.app.root, and each hierarchical
-    component in the path_info argument is matched to a corresponding nested
-    attribute of the root object. Matching handlers must have an 'exposed'
-    attribute which evaluates to True. The special method name "index"
-    matches a URI which ends in a slash ("/"). The special method name
-    "default" may match a portion of the path_info (but only when no longer
-    substring of the path_info matches some other object).
-    
-    This is the default, built-in dispatcher for CherryPy.
-    """
-    __metaclass__ = cherrypy._AttributeDocstrings
-
-    dispatch_method_name = '_cp_dispatch'
-    dispatch_method_name__doc = """
-    The name of the dispatch method that nodes may optionally implement
-    to provide their own dynamic dispatch algorithm.
-    """
-    
-    def __init__(self, dispatch_method_name = None):
-        if dispatch_method_name:
-            self.dispatch_method_name = dispatch_method_name
-
-    def __call__(self, path_info):
-        """Set handler and config for the current request."""
-        request = cherrypy.serving.request
-        func, vpath = self.find_handler(path_info)
-        
-        if func:
-            # Decode any leftover %2F in the virtual_path atoms.
-            vpath = [x.replace("%2F", "/") for x in vpath]
-            request.handler = LateParamPageHandler(func, *vpath)
-        else:
-            request.handler = cherrypy.NotFound()
-    
-    def find_handler(self, path):
-        """Return the appropriate page handler, plus any virtual path.
-        
-        This will return two objects. The first will be a callable,
-        which can be used to generate page output. Any parameters from
-        the query string or request body will be sent to that callable
-        as keyword arguments.
-        
-        The callable is found by traversing the application's tree,
-        starting from cherrypy.request.app.root, and matching path
-        components to successive objects in the tree. For example, the
-        URL "/path/to/handler" might return root.path.to.handler.
-        
-        The second object returned will be a list of names which are
-        'virtual path' components: parts of the URL which are dynamic,
-        and were not used when looking up the handler.
-        These virtual path components are passed to the handler as
-        positional arguments.
-        """
-        request = cherrypy.serving.request
-        app = request.app
-        root = app.root
-        dispatch_name = self.dispatch_method_name
-        
-        # Get config for the root object/path.
-        curpath = ""
-        nodeconf = {}
-        if hasattr(root, "_cp_config"):
-            nodeconf.update(root._cp_config)
-        if "/" in app.config:
-            nodeconf.update(app.config["/"])
-        object_trail = [['root', root, nodeconf, curpath]]
-        
-        node = root
-        names = [x for x in path.strip('/').split('/') if x] + ['index']
-        iternames = names[:]
-        while iternames:
-            name = iternames[0]
-            # map to legal Python identifiers (replace '.' with '_')
-            objname = name.replace('.', '_')
-            
-            nodeconf = {}
-            subnode = getattr(node, objname, None)
-            if subnode is None:
-                dispatch = getattr(node, dispatch_name, None)
-                if dispatch and callable(dispatch) and not \
-                        getattr(dispatch, 'exposed', False):
-                    subnode = dispatch(vpath=iternames)
-            name = iternames.pop(0)
-            node = subnode
-
-            if node is not None:
-                # Get _cp_config attached to this node.
-                if hasattr(node, "_cp_config"):
-                    nodeconf.update(node._cp_config)
-            
-            # Mix in values from app.config for this path.
-            curpath = "/".join((curpath, name))
-            if curpath in app.config:
-                nodeconf.update(app.config[curpath])
-            
-            object_trail.append([name, node, nodeconf, curpath])
-        
-        def set_conf():
-            """Collapse all object_trail config into cherrypy.request.config."""
-            base = cherrypy.config.copy()
-            # Note that we merge the config from each node
-            # even if that node was None.
-            for name, obj, conf, curpath in object_trail:
-                base.update(conf)
-                if 'tools.staticdir.dir' in conf:
-                    base['tools.staticdir.section'] = curpath
-            return base
-        
-        # Try successive objects (reverse order)
-        num_candidates = len(object_trail) - 1
-        for i in range(num_candidates, -1, -1):
-            
-            name, candidate, nodeconf, curpath = object_trail[i]
-            if candidate is None:
-                continue
-            
-            # Try a "default" method on the current leaf.
-            if hasattr(candidate, "default"):
-                defhandler = candidate.default
-                if getattr(defhandler, 'exposed', False):
-                    # Insert any extra _cp_config from the default handler.
-                    conf = getattr(defhandler, "_cp_config", {})
-                    object_trail.insert(i+1, ["default", defhandler, conf, curpath])
-                    request.config = set_conf()
-                    # See http://www.cherrypy.org/ticket/613
-                    request.is_index = path.endswith("/")
-                    return defhandler, names[i:-1]
-            
-            # Uncomment the next line to restrict positional params to "default".
-            # if i < num_candidates - 2: continue
-            
-            # Try the current leaf.
-            if getattr(candidate, 'exposed', False):
-                request.config = set_conf()
-                if i == num_candidates:
-                    # We found the extra ".index". Mark request so tools
-                    # can redirect if path_info has no trailing slash.
-                    request.is_index = True
-                else:
-                    # We're not at an 'index' handler. Mark request so tools
-                    # can redirect if path_info has NO trailing slash.
-                    # Note that this also includes handlers which take
-                    # positional parameters (virtual paths).
-                    request.is_index = False
-                return candidate, names[i:-1]
-        
-        # We didn't find anything
-        request.config = set_conf()
-        return None, []
-
-
-class MethodDispatcher(Dispatcher):
-    """Additional dispatch based on cherrypy.request.method.upper().
-    
-    Methods named GET, POST, etc will be called on an exposed class.
-    The method names must be all caps; the appropriate Allow header
-    will be output showing all capitalized method names as allowable
-    HTTP verbs.
-    
-    Note that the containing class must be exposed, not the methods.
-    """
-    
-    def __call__(self, path_info):
-        """Set handler and config for the current request."""
-        request = cherrypy.serving.request
-        resource, vpath = self.find_handler(path_info)
-        
-        if resource:
-            # Set Allow header
-            avail = [m for m in dir(resource) if m.isupper()]
-            if "GET" in avail and "HEAD" not in avail:
-                avail.append("HEAD")
-            avail.sort()
-            cherrypy.serving.response.headers['Allow'] = ", ".join(avail)
-            
-            # Find the subhandler
-            meth = request.method.upper()
-            func = getattr(resource, meth, None)
-            if func is None and meth == "HEAD":
-                func = getattr(resource, "GET", None)
-            if func:
-                # Grab any _cp_config on the subhandler.
-                if hasattr(func, "_cp_config"):
-                    request.config.update(func._cp_config)
-                
-                # Decode any leftover %2F in the virtual_path atoms.
-                vpath = [x.replace("%2F", "/") for x in vpath]
-                request.handler = LateParamPageHandler(func, *vpath)
-            else:
-                request.handler = cherrypy.HTTPError(405)
-        else:
-            request.handler = cherrypy.NotFound()
-
-
-class RoutesDispatcher(object):
-    """A Routes based dispatcher for CherryPy."""
-    
-    def __init__(self, full_result=False):
-        """
-        Routes dispatcher
-
-        Set full_result to True if you wish the controller
-        and the action to be passed on to the page handler
-        parameters. By default they won't be.
-        """
-        import routes
-        self.full_result = full_result
-        self.controllers = {}
-        self.mapper = routes.Mapper()
-        self.mapper.controller_scan = self.controllers.keys
-        
-    def connect(self, name, route, controller, **kwargs):
-        self.controllers[name] = controller
-        self.mapper.connect(name, route, controller=name, **kwargs)
-    
-    def redirect(self, url):
-        raise cherrypy.HTTPRedirect(url)
-    
-    def __call__(self, path_info):
-        """Set handler and config for the current request."""
-        func = self.find_handler(path_info)
-        if func:
-            cherrypy.serving.request.handler = LateParamPageHandler(func)
-        else:
-            cherrypy.serving.request.handler = cherrypy.NotFound()
-    
-    def find_handler(self, path_info):
-        """Find the right page handler, and set request.config."""
-        import routes
-        
-        request = cherrypy.serving.request
-        
-        config = routes.request_config()
-        config.mapper = self.mapper
-        if hasattr(request, 'wsgi_environ'):
-            config.environ = request.wsgi_environ
-        config.host = request.headers.get('Host', None)
-        config.protocol = request.scheme
-        config.redirect = self.redirect
-        
-        result = self.mapper.match(path_info)
-        
-        config.mapper_dict = result
-        params = {}
-        if result:
-            params = result.copy()
-        if not self.full_result:
-            params.pop('controller', None)
-            params.pop('action', None)
-        request.params.update(params)
-        
-        # Get config for the root object/path.
-        request.config = base = cherrypy.config.copy()
-        curpath = ""
-        
-        def merge(nodeconf):
-            if 'tools.staticdir.dir' in nodeconf:
-                nodeconf['tools.staticdir.section'] = curpath or "/"
-            base.update(nodeconf)
-        
-        app = request.app
-        root = app.root
-        if hasattr(root, "_cp_config"):
-            merge(root._cp_config)
-        if "/" in app.config:
-            merge(app.config["/"])
-        
-        # Mix in values from app.config.
-        atoms = [x for x in path_info.split("/") if x]
-        if atoms:
-            last = atoms.pop()
-        else:
-            last = None
-        for atom in atoms:
-            curpath = "/".join((curpath, atom))
-            if curpath in app.config:
-                merge(app.config[curpath])
-        
-        handler = None
-        if result:
-            controller = result.get('controller', None)
-            controller = self.controllers.get(controller)
-            if controller:
-                # Get config from the controller.
-                if hasattr(controller, "_cp_config"):
-                    merge(controller._cp_config)
-            
-            action = result.get('action', None)
-            if action is not None:
-                handler = getattr(controller, action, None)
-                # Get config from the handler 
-                if hasattr(handler, "_cp_config"): 
-                    merge(handler._cp_config)
-                    
-        # Do the last path atom here so it can
-        # override the controller's _cp_config.
-        if last:
-            curpath = "/".join((curpath, last))
-            if curpath in app.config:
-                merge(app.config[curpath])
-        
-        return handler
-
-
-def XMLRPCDispatcher(next_dispatcher=Dispatcher()):
-    from cherrypy.lib import xmlrpc
-    def xmlrpc_dispatch(path_info):
-        path_info = xmlrpc.patched_path(path_info)
-        return next_dispatcher(path_info)
-    return xmlrpc_dispatch
-
-
-def VirtualHost(next_dispatcher=Dispatcher(), use_x_forwarded_host=True, **domains):
-    """Select a different handler based on the Host header.
-    
-    This can be useful when running multiple sites within one CP server.
-    It allows several domains to point to different parts of a single
-    website structure. For example:
-    
-        http://www.domain.example  ->  root
-        http://www.domain2.example  ->  root/domain2/
-        http://www.domain2.example:443  ->  root/secure
-    
-    can be accomplished via the following config:
-    
-        [/]
-        request.dispatch = cherrypy.dispatch.VirtualHost(
-            **{'www.domain2.example': '/domain2',
-               'www.domain2.example:443': '/secure',
-              })
-    
-    next_dispatcher: the next dispatcher object in the dispatch chain.
-        The VirtualHost dispatcher adds a prefix to the URL and calls
-        another dispatcher. Defaults to cherrypy.dispatch.Dispatcher().
-    
-    use_x_forwarded_host: if True (the default), any "X-Forwarded-Host"
-        request header will be used instead of the "Host" header. This
-        is commonly added by HTTP servers (such as Apache) when proxying.
-    
-    **domains: a dict of {host header value: virtual prefix} pairs.
-        The incoming "Host" request header is looked up in this dict,
-        and, if a match is found, the corresponding "virtual prefix"
-        value will be prepended to the URL path before calling the
-        next dispatcher. Note that you often need separate entries
-        for "example.com" and "www.example.com". In addition, "Host"
-        headers may contain the port number.
-    """
-    from cherrypy.lib import httputil
-    def vhost_dispatch(path_info):
-        request = cherrypy.serving.request
-        header = request.headers.get
-        
-        domain = header('Host', '')
-        if use_x_forwarded_host:
-            domain = header("X-Forwarded-Host", domain)
-        
-        prefix = domains.get(domain, "")
-        if prefix:
-            path_info = httputil.urljoin(prefix, path_info)
-        
-        result = next_dispatcher(path_info)
-        
-        # Touch up staticdir config. See http://www.cherrypy.org/ticket/614.
-        section = request.config.get('tools.staticdir.section')
-        if section:
-            section = section[len(prefix):]
-            request.config['tools.staticdir.section'] = section
-        
-        return result
-    return vhost_dispatch
-
--- a/bundled/cherrypy/cherrypy/_cperror.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,396 +0,0 @@
-"""Error classes for CherryPy."""
-
-from cgi import escape as _escape
-from sys import exc_info as _exc_info
-from traceback import format_exception as _format_exception
-from urlparse import urljoin as _urljoin
-from cherrypy.lib import httputil as _httputil
-
-
-class CherryPyException(Exception):
-    pass
-
-
-class TimeoutError(CherryPyException):
-    """Exception raised when Response.timed_out is detected."""
-    pass
-
-
-class InternalRedirect(CherryPyException):
-    """Exception raised to switch to the handler for a different URL.
-    
-    Any request.params must be supplied in a query string.
-    """
-    
-    def __init__(self, path, query_string=""):
-        import cherrypy
-        self.request = cherrypy.serving.request
-        
-        self.query_string = query_string
-        if "?" in path:
-            # Separate any params included in the path
-            path, self.query_string = path.split("?", 1)
-        
-        # Note that urljoin will "do the right thing" whether url is:
-        #  1. a URL relative to root (e.g. "/dummy")
-        #  2. a URL relative to the current path
-        # Note that any query string will be discarded.
-        path = _urljoin(self.request.path_info, path)
-        
-        # Set a 'path' member attribute so that code which traps this
-        # error can have access to it.
-        self.path = path
-        
-        CherryPyException.__init__(self, path, self.query_string)
-
-
-class HTTPRedirect(CherryPyException):
-    """Exception raised when the request should be redirected.
-    
-    The new URL must be passed as the first argument to the Exception,
-    e.g., HTTPRedirect(newUrl). Multiple URLs are allowed. If a URL is
-    absolute, it will be used as-is. If it is relative, it is assumed
-    to be relative to the current cherrypy.request.path_info.
-    """
-    
-    def __init__(self, urls, status=None):
-        import cherrypy
-        request = cherrypy.serving.request
-        
-        if isinstance(urls, basestring):
-            urls = [urls]
-        
-        abs_urls = []
-        for url in urls:
-            # Note that urljoin will "do the right thing" whether url is:
-            #  1. a complete URL with host (e.g. "http://www.example.com/test")
-            #  2. a URL relative to root (e.g. "/dummy")
-            #  3. a URL relative to the current path
-            # Note that any query string in cherrypy.request is discarded.
-            url = _urljoin(cherrypy.url(), url)
-            abs_urls.append(url)
-        self.urls = abs_urls
-        
-        # RFC 2616 indicates a 301 response code fits our goal; however,
-        # browser support for 301 is quite messy. Do 302/303 instead. See
-        # http://www.alanflavell.org.uk/www/post-redirect.html
-        if status is None:
-            if request.protocol >= (1, 1):
-                status = 303
-            else:
-                status = 302
-        else:
-            status = int(status)
-            if status < 300 or status > 399:
-                raise ValueError("status must be between 300 and 399.")
-        
-        self.status = status
-        CherryPyException.__init__(self, abs_urls, status)
-    
-    def set_response(self):
-        """Modify cherrypy.response status, headers, and body to represent self.
-        
-        CherryPy uses this internally, but you can also use it to create an
-        HTTPRedirect object and set its output without *raising* the exception.
-        """
-        import cherrypy
-        response = cherrypy.serving.response
-        response.status = status = self.status
-        
-        if status in (300, 301, 302, 303, 307):
-            response.headers['Content-Type'] = "text/html;charset=utf-8"
-            # "The ... URI SHOULD be given by the Location field
-            # in the response."
-            response.headers['Location'] = self.urls[0]
-            
-            # "Unless the request method was HEAD, the entity of the response
-            # SHOULD contain a short hypertext note with a hyperlink to the
-            # new URI(s)."
-            msg = {300: "This resource can be found at <a href='%s'>%s</a>.",
-                   301: "This resource has permanently moved to <a href='%s'>%s</a>.",
-                   302: "This resource resides temporarily at <a href='%s'>%s</a>.",
-                   303: "This resource can be found at <a href='%s'>%s</a>.",
-                   307: "This resource has moved temporarily to <a href='%s'>%s</a>.",
-                   }[status]
-            msgs = [msg % (u, u) for u in self.urls]
-            response.body = "<br />\n".join(msgs)
-            # Previous code may have set C-L, so we have to reset it
-            # (allow finalize to set it).
-            response.headers.pop('Content-Length', None)
-        elif status == 304:
-            # Not Modified.
-            # "The response MUST include the following header fields:
-            # Date, unless its omission is required by section 14.18.1"
-            # The "Date" header should have been set in Response.__init__
-            
-            # "...the response SHOULD NOT include other entity-headers."
-            for key in ('Allow', 'Content-Encoding', 'Content-Language',
-                        'Content-Length', 'Content-Location', 'Content-MD5',
-                        'Content-Range', 'Content-Type', 'Expires',
-                        'Last-Modified'):
-                if key in response.headers:
-                    del response.headers[key]
-            
-            # "The 304 response MUST NOT contain a message-body."
-            response.body = None
-            # Previous code may have set C-L, so we have to reset it.
-            response.headers.pop('Content-Length', None)
-        elif status == 305:
-            # Use Proxy.
-            # self.urls[0] should be the URI of the proxy.
-            response.headers['Location'] = self.urls[0]
-            response.body = None
-            # Previous code may have set C-L, so we have to reset it.
-            response.headers.pop('Content-Length', None)
-        else:
-            raise ValueError("The %s status code is unknown." % status)
-    
-    def __call__(self):
-        """Use this exception as a request.handler (raise self)."""
-        raise self
-
-
-def clean_headers(status):
-    """Remove any headers which should not apply to an error response."""
-    import cherrypy
-    
-    response = cherrypy.serving.response
-    
-    # Remove headers which applied to the original content,
-    # but do not apply to the error page.
-    respheaders = response.headers
-    for key in ["Accept-Ranges", "Age", "ETag", "Location", "Retry-After",
-                "Vary", "Content-Encoding", "Content-Length", "Expires",
-                "Content-Location", "Content-MD5", "Last-Modified"]:
-        if key in respheaders:
-            del respheaders[key]
-    
-    if status != 416:
-        # A server sending a response with status code 416 (Requested
-        # range not satisfiable) SHOULD include a Content-Range field
-        # with a byte-range-resp-spec of "*". The instance-length
-        # specifies the current length of the selected resource.
-        # A response with status code 206 (Partial Content) MUST NOT
-        # include a Content-Range field with a byte-range- resp-spec of "*".
-        if "Content-Range" in respheaders:
-            del respheaders["Content-Range"]
-
-
-class HTTPError(CherryPyException):
-    """ Exception used to return an HTTP error code (4xx-5xx) to the client.
-        This exception will automatically set the response status and body.
-        
-        A custom message (a long description to display in the browser)
-        can be provided in place of the default.
-    """
-    
-    def __init__(self, status=500, message=None):
-        self.status = status
-        try:
-            self.code, self.reason, defaultmsg = _httputil.valid_status(status)
-        except ValueError, x:
-            raise self.__class__(500, x.args[0])
-        
-        if self.code < 400 or self.code > 599:
-            raise ValueError("status must be between 400 and 599.")
-        
-        # See http://www.python.org/dev/peps/pep-0352/
-        # self.message = message
-        self._message = message or defaultmsg
-        CherryPyException.__init__(self, status, message)
-    
-    def set_response(self):
-        """Modify cherrypy.response status, headers, and body to represent self.
-        
-        CherryPy uses this internally, but you can also use it to create an
-        HTTPError object and set its output without *raising* the exception.
-        """
-        import cherrypy
-        
-        response = cherrypy.serving.response
-        
-        clean_headers(self.code)
-        
-        # In all cases, finalize will be called after this method,
-        # so don't bother cleaning up response values here.
-        response.status = self.status
-        tb = None
-        if cherrypy.serving.request.show_tracebacks:
-            tb = format_exc()
-        response.headers['Content-Type'] = "text/html;charset=utf-8"
-        response.headers.pop('Content-Length', None)
-        
-        content = self.get_error_page(self.status, traceback=tb,
-                                      message=self._message)
-        response.body = content
-        
-        _be_ie_unfriendly(self.code)
-    
-    def get_error_page(self, *args, **kwargs):
-        return get_error_page(*args, **kwargs)
-    
-    def __call__(self):
-        """Use this exception as a request.handler (raise self)."""
-        raise self
-
-
-class NotFound(HTTPError):
-    """Exception raised when a URL could not be mapped to any handler (404)."""
-    
-    def __init__(self, path=None):
-        if path is None:
-            import cherrypy
-            request = cherrypy.serving.request
-            path = request.script_name + request.path_info
-        self.args = (path,)
-        HTTPError.__init__(self, 404, "The path '%s' was not found." % path)
-
-
-_HTTPErrorTemplate = '''<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html>
-<head>
-    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
-    <title>%(status)s</title>
-    <style type="text/css">
-    #powered_by {
-        margin-top: 20px;
-        border-top: 2px solid black;
-        font-style: italic;
-    }
-
-    #traceback {
-        color: red;
-    }
-    </style>
-</head>
-    <body>
-        <h2>%(status)s</h2>
-        <p>%(message)s</p>
-        <pre id="traceback">%(traceback)s</pre>
-    <div id="powered_by">
-    <span>Powered by <a href="http://www.cherrypy.org">CherryPy %(version)s</a></span>
-    </div>
-    </body>
-</html>
-'''
-
-def get_error_page(status, **kwargs):
-    """Return an HTML page, containing a pretty error response.
-    
-    status should be an int or a str.
-    kwargs will be interpolated into the page template.
-    """
-    import cherrypy
-    
-    try:
-        code, reason, message = _httputil.valid_status(status)
-    except ValueError, x:
-        raise cherrypy.HTTPError(500, x.args[0])
-    
-    # We can't use setdefault here, because some
-    # callers send None for kwarg values.
-    if kwargs.get('status') is None:
-        kwargs['status'] = "%s %s" % (code, reason)
-    if kwargs.get('message') is None:
-        kwargs['message'] = message
-    if kwargs.get('traceback') is None:
-        kwargs['traceback'] = ''
-    if kwargs.get('version') is None:
-        kwargs['version'] = cherrypy.__version__
-    
-    for k, v in kwargs.iteritems():
-        if v is None:
-            kwargs[k] = ""
-        else:
-            kwargs[k] = _escape(kwargs[k])
-    
-    # Use a custom template or callable for the error page?
-    pages = cherrypy.serving.request.error_page
-    error_page = pages.get(code) or pages.get('default')
-    if error_page:
-        try:
-            if callable(error_page):
-                return error_page(**kwargs)
-            else:
-                return open(error_page, 'rb').read() % kwargs
-        except:
-            e = _format_exception(*_exc_info())[-1]
-            m = kwargs['message']
-            if m:
-                m += "<br />"
-            m += "In addition, the custom error page failed:\n<br />%s" % e
-            kwargs['message'] = m
-    
-    return _HTTPErrorTemplate % kwargs
-
-
-_ie_friendly_error_sizes = {
-    400: 512, 403: 256, 404: 512, 405: 256,
-    406: 512, 408: 512, 409: 512, 410: 256,
-    500: 512, 501: 512, 505: 512,
-    }
-
-
-def _be_ie_unfriendly(status):
-    import cherrypy
-    response = cherrypy.serving.response
-    
-    # For some statuses, Internet Explorer 5+ shows "friendly error
-    # messages" instead of our response.body if the body is smaller
-    # than a given size. Fix this by returning a body over that size
-    # (by adding whitespace).
-    # See http://support.microsoft.com/kb/q218155/
-    s = _ie_friendly_error_sizes.get(status, 0)
-    if s:
-        s += 1
-        # Since we are issuing an HTTP error status, we assume that
-        # the entity is short, and we should just collapse it.
-        content = response.collapse_body()
-        l = len(content)
-        if l and l < s:
-            # IN ADDITION: the response must be written to IE
-            # in one chunk or it will still get replaced! Bah.
-            content = content + (" " * (s - l))
-        response.body = content
-        response.headers[u'Content-Length'] = str(len(content))
-
-
-def format_exc(exc=None):
-    """Return exc (or sys.exc_info if None), formatted."""
-    if exc is None:
-        exc = _exc_info()
-    if exc == (None, None, None):
-        return ""
-    import traceback
-    return "".join(traceback.format_exception(*exc))
-
-def bare_error(extrabody=None):
-    """Produce status, headers, body for a critical error.
-    
-    Returns a triple without calling any other questionable functions,
-    so it should be as error-free as possible. Call it from an HTTP server
-    if you get errors outside of the request.
-    
-    If extrabody is None, a friendly but rather unhelpful error message
-    is set in the body. If extrabody is a string, it will be appended
-    as-is to the body.
-    """
-    
-    # The whole point of this function is to be a last line-of-defense
-    # in handling errors. That is, it must not raise any errors itself;
-    # it cannot be allowed to fail. Therefore, don't add to it!
-    # In particular, don't call any other CP functions.
-    
-    body = "Unrecoverable error in the server."
-    if extrabody is not None:
-        if not isinstance(extrabody, str): 
-            extrabody = extrabody.encode('utf-8')
-        body += "\n" + extrabody
-    
-    return ("500 Internal Server Error",
-            [('Content-Type', 'text/plain'),
-             ('Content-Length', str(len(body)))],
-            [body])
-
-
--- a/bundled/cherrypy/cherrypy/_cplogging.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,250 +0,0 @@
-"""CherryPy logging."""
-
-import datetime
-import logging
-# Silence the no-handlers "warning" (stderr write!) in stdlib logging
-logging.Logger.manager.emittedNoHandlerWarning = 1
-logfmt = logging.Formatter("%(message)s")
-import os
-import sys
-
-import cherrypy
-from cherrypy import _cperror
-
-
-class LogManager(object):
-    
-    appid = None
-    error_log = None
-    access_log = None
-    access_log_format = \
-        '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
-    
-    def __init__(self, appid=None, logger_root="cherrypy"):
-        self.logger_root = logger_root
-        self.appid = appid
-        if appid is None:
-            self.error_log = logging.getLogger("%s.error" % logger_root)
-            self.access_log = logging.getLogger("%s.access" % logger_root)
-        else:
-            self.error_log = logging.getLogger("%s.error.%s" % (logger_root, appid))
-            self.access_log = logging.getLogger("%s.access.%s" % (logger_root, appid))
-        self.error_log.setLevel(logging.INFO)
-        self.access_log.setLevel(logging.INFO)
-        cherrypy.engine.subscribe('graceful', self.reopen_files)
-    
-    def reopen_files(self):
-        """Close and reopen all file handlers."""
-        for log in (self.error_log, self.access_log):
-            for h in log.handlers:
-                if isinstance(h, logging.FileHandler):
-                    h.acquire()
-                    h.stream.close()
-                    h.stream = open(h.baseFilename, h.mode)
-                    h.release()
-    
-    def error(self, msg='', context='', severity=logging.INFO, traceback=False):
-        """Write to the error log.
-        
-        This is not just for errors! Applications may call this at any time
-        to log application-specific information.
-        """
-        if traceback:
-            msg += _cperror.format_exc()
-        self.error_log.log(severity, ' '.join((self.time(), context, msg)))
-    
-    def __call__(self, *args, **kwargs):
-        """Write to the error log.
-        
-        This is not just for errors! Applications may call this at any time
-        to log application-specific information.
-        """
-        return self.error(*args, **kwargs)
-    
-    def access(self):
-        """Write to the access log (in Apache/NCSA Combined Log format).
-        
-        Like Apache started doing in 2.0.46, non-printable and other special
-        characters in %r (and we expand that to all parts) are escaped using
-        \\xhh sequences, where hh stands for the hexadecimal representation
-        of the raw byte. Exceptions from this rule are " and \\, which are
-        escaped by prepending a backslash, and all whitespace characters,
-        which are written in their C-style notation (\\n, \\t, etc).
-        """
-        request = cherrypy.serving.request
-        remote = request.remote
-        response = cherrypy.serving.response
-        outheaders = response.headers
-        inheaders = request.headers
-        if response.output_status is None:
-            status = "-"
-        else:
-            status = response.output_status.split(" ", 1)[0]
-        
-        atoms = {'h': remote.name or remote.ip,
-                 'l': '-',
-                 'u': getattr(request, "login", None) or "-",
-                 't': self.time(),
-                 'r': request.request_line,
-                 's': status,
-                 'b': dict.get(outheaders, 'Content-Length', '') or "-",
-                 'f': dict.get(inheaders, 'Referer', ''),
-                 'a': dict.get(inheaders, 'User-Agent', ''),
-                 }
-        for k, v in atoms.items():
-            if isinstance(v, unicode):
-                v = v.encode('utf8')
-            elif not isinstance(v, str):
-                v = str(v)
-            # Fortunately, repr(str) escapes unprintable chars, \n, \t, etc
-            # and backslash for us. All we have to do is strip the quotes.
-            v = repr(v)[1:-1]
-            # Escape double-quote.
-            atoms[k] = v.replace('"', '\\"')
-        
-        try:
-            self.access_log.log(logging.INFO, self.access_log_format % atoms)
-        except:
-            self(traceback=True)
-    
-    def time(self):
-        """Return now() in Apache Common Log Format (no timezone)."""
-        now = datetime.datetime.now()
-        monthnames = ['jan', 'feb', 'mar', 'apr', 'may', 'jun',
-                      'jul', 'aug', 'sep', 'oct', 'nov', 'dec']
-        month = monthnames[now.month - 1].capitalize()
-        return ('[%02d/%s/%04d:%02d:%02d:%02d]' %
-                (now.day, month, now.year, now.hour, now.minute, now.second))
-    
-    def _get_builtin_handler(self, log, key):
-        for h in log.handlers:
-            if getattr(h, "_cpbuiltin", None) == key:
-                return h
-    
-    
-    # ------------------------- Screen handlers ------------------------- #
-    
-    def _set_screen_handler(self, log, enable, stream=None):
-        h = self._get_builtin_handler(log, "screen")
-        if enable:
-            if not h:
-                if stream is None:
-                    stream=sys.stderr
-                h = logging.StreamHandler(stream)
-                h.setFormatter(logfmt)
-                h._cpbuiltin = "screen"
-                log.addHandler(h)
-        elif h:
-            log.handlers.remove(h)
-    
-    def _get_screen(self):
-        h = self._get_builtin_handler
-        has_h = h(self.error_log, "screen") or h(self.access_log, "screen")
-        return bool(has_h)
-    
-    def _set_screen(self, newvalue):
-        self._set_screen_handler(self.error_log, newvalue, stream=sys.stderr)
-        self._set_screen_handler(self.access_log, newvalue, stream=sys.stdout)
-    screen = property(_get_screen, _set_screen,
-                      doc="If True, error and access will print to stderr.")
-    
-    
-    # -------------------------- File handlers -------------------------- #
-    
-    def _add_builtin_file_handler(self, log, fname):
-        h = logging.FileHandler(fname)
-        h.setFormatter(logfmt)
-        h._cpbuiltin = "file"
-        log.addHandler(h)
-    
-    def _set_file_handler(self, log, filename):
-        h = self._get_builtin_handler(log, "file")
-        if filename:
-            if h:
-                if h.baseFilename != os.path.abspath(filename):
-                    h.close()
-                    log.handlers.remove(h)
-                    self._add_builtin_file_handler(log, filename)
-            else:
-                self._add_builtin_file_handler(log, filename)
-        else:
-            if h:
-                h.close()
-                log.handlers.remove(h)
-    
-    def _get_error_file(self):
-        h = self._get_builtin_handler(self.error_log, "file")
-        if h:
-            return h.baseFilename
-        return ''
-    def _set_error_file(self, newvalue):
-        self._set_file_handler(self.error_log, newvalue)
-    error_file = property(_get_error_file, _set_error_file,
-                          doc="The filename for self.error_log.")
-    
-    def _get_access_file(self):
-        h = self._get_builtin_handler(self.access_log, "file")
-        if h:
-            return h.baseFilename
-        return ''
-    def _set_access_file(self, newvalue):
-        self._set_file_handler(self.access_log, newvalue)
-    access_file = property(_get_access_file, _set_access_file,
-                           doc="The filename for self.access_log.")
-    
-    
-    # ------------------------- WSGI handlers ------------------------- #
-    
-    def _set_wsgi_handler(self, log, enable):
-        h = self._get_builtin_handler(log, "wsgi")
-        if enable:
-            if not h:
-                h = WSGIErrorHandler()
-                h.setFormatter(logfmt)
-                h._cpbuiltin = "wsgi"
-                log.addHandler(h)
-        elif h:
-            log.handlers.remove(h)
-    
-    def _get_wsgi(self):
-        return bool(self._get_builtin_handler(self.error_log, "wsgi"))
-    
-    def _set_wsgi(self, newvalue):
-        self._set_wsgi_handler(self.error_log, newvalue)
-    wsgi = property(_get_wsgi, _set_wsgi,
-                      doc="If True, error messages will be sent to wsgi.errors.")
-
-
-class WSGIErrorHandler(logging.Handler):
-    "A handler class which writes logging records to environ['wsgi.errors']."
-    
-    def flush(self):
-        """Flushes the stream."""
-        try:
-            stream = cherrypy.serving.request.wsgi_environ.get('wsgi.errors')
-        except (AttributeError, KeyError):
-            pass
-        else:
-            stream.flush()
-    
-    def emit(self, record):
-        """Emit a record."""
-        try:
-            stream = cherrypy.serving.request.wsgi_environ.get('wsgi.errors')
-        except (AttributeError, KeyError):
-            pass
-        else:
-            try:
-                msg = self.format(record)
-                fs = "%s\n"
-                import types
-                if not hasattr(types, "UnicodeType"): #if no unicode support...
-                    stream.write(fs % msg)
-                else:
-                    try:
-                        stream.write(fs % msg)
-                    except UnicodeError:
-                        stream.write(fs % msg.encode("UTF-8"))
-                self.flush()
-            except:
-                self.handleError(record)
--- a/bundled/cherrypy/cherrypy/_cpmodpy.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,333 +0,0 @@
-"""Native adapter for serving CherryPy via mod_python
-
-Basic usage:
-
-##########################################
-# Application in a module called myapp.py
-##########################################
-
-import cherrypy
-
-class Root:
-    @cherrypy.expose
-    def index(self):
-        return 'Hi there, Ho there, Hey there'
-
-
-# We will use this method from the mod_python configuration
-# as the entry point to our application
-def setup_server():
-    cherrypy.tree.mount(Root())
-    cherrypy.config.update({'environment': 'production',
-                            'log.screen': False,
-                            'show_tracebacks': False})
-
-##########################################
-# mod_python settings for apache2
-# This should reside in your httpd.conf
-# or a file that will be loaded at
-# apache startup
-##########################################
-
-# Start
-DocumentRoot "/"
-Listen 8080
-LoadModule python_module /usr/lib/apache2/modules/mod_python.so
-
-<Location "/">
-	PythonPath "sys.path+['/path/to/my/application']" 
-	SetHandler python-program
-	PythonHandler cherrypy._cpmodpy::handler
-	PythonOption cherrypy.setup myapp::setup_server
-	PythonDebug On
-</Location> 
-# End
-
-The actual path to your mod_python.so is dependent on your
-environment. In this case we suppose a global mod_python
-installation on a Linux distribution such as Ubuntu.
-
-We do set the PythonPath configuration setting so that
-your application can be found by from the user running
-the apache2 instance. Of course if your application
-resides in the global site-package this won't be needed.
-
-Then restart apache2 and access http://127.0.0.1:8080
-"""
-
-import logging
-try:
-    from cStringIO import StringIO
-except ImportError:
-    from StringIO import StringIO
-
-import cherrypy
-from cherrypy._cperror import format_exc, bare_error
-from cherrypy.lib import httputil
-
-
-# ------------------------------ Request-handling
-
-
-
-def setup(req):
-    from mod_python import apache
-    
-    # Run any setup functions defined by a "PythonOption cherrypy.setup" directive.
-    options = req.get_options()
-    if 'cherrypy.setup' in options:
-        for function in options['cherrypy.setup'].split():
-            atoms = function.split('::', 1)
-            if len(atoms) == 1:
-                mod = __import__(atoms[0], globals(), locals())
-            else:
-                modname, fname = atoms
-                mod = __import__(modname, globals(), locals(), [fname])
-                func = getattr(mod, fname)
-                func()
-    
-    cherrypy.config.update({'log.screen': False,
-                            "tools.ignore_headers.on": True,
-                            "tools.ignore_headers.headers": ['Range'],
-                            })
-    
-    engine = cherrypy.engine
-    if hasattr(engine, "signal_handler"):
-        engine.signal_handler.unsubscribe()
-    if hasattr(engine, "console_control_handler"):
-        engine.console_control_handler.unsubscribe()
-    engine.autoreload.unsubscribe()
-    cherrypy.server.unsubscribe()
-    
-    def _log(msg, level):
-        newlevel = apache.APLOG_ERR
-        if logging.DEBUG >= level:
-            newlevel = apache.APLOG_DEBUG
-        elif logging.INFO >= level:
-            newlevel = apache.APLOG_INFO
-        elif logging.WARNING >= level:
-            newlevel = apache.APLOG_WARNING
-        # On Windows, req.server is required or the msg will vanish. See
-        # http://www.modpython.org/pipermail/mod_python/2003-October/014291.html.
-        # Also, "When server is not specified...LogLevel does not apply..."
-        apache.log_error(msg, newlevel, req.server)
-    engine.subscribe('log', _log)
-    
-    engine.start()
-    
-    def cherrypy_cleanup(data):
-        engine.exit()
-    try:
-        # apache.register_cleanup wasn't available until 3.1.4.
-        apache.register_cleanup(cherrypy_cleanup)
-    except AttributeError:
-        req.server.register_cleanup(req, cherrypy_cleanup)
-
-
-class _ReadOnlyRequest:
-    expose = ('read', 'readline', 'readlines')
-    def __init__(self, req):
-        for method in self.expose:
-            self.__dict__[method] = getattr(req, method)
-
-
-recursive = False
-
-_isSetUp = False
-def handler(req):
-    from mod_python import apache
-    try:
-        global _isSetUp
-        if not _isSetUp:
-            setup(req)
-            _isSetUp = True
-        
-        # Obtain a Request object from CherryPy
-        local = req.connection.local_addr
-        local = httputil.Host(local[0], local[1], req.connection.local_host or "")
-        remote = req.connection.remote_addr
-        remote = httputil.Host(remote[0], remote[1], req.connection.remote_host or "")
-        
-        scheme = req.parsed_uri[0] or 'http'
-        req.get_basic_auth_pw()
-        
-        try:
-            # apache.mpm_query only became available in mod_python 3.1
-            q = apache.mpm_query
-            threaded = q(apache.AP_MPMQ_IS_THREADED)
-            forked = q(apache.AP_MPMQ_IS_FORKED)
-        except AttributeError:
-            bad_value = ("You must provide a PythonOption '%s', "
-                         "either 'on' or 'off', when running a version "
-                         "of mod_python < 3.1")
-            
-            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")
-        
-        sn = cherrypy.tree.script_name(req.uri or "/")
-        if sn is None:
-            send_response(req, '404 Not Found', [], '')
-        else:
-            app = cherrypy.tree.apps[sn]
-            method = req.method
-            path = req.uri
-            qs = req.args or ""
-            reqproto = req.protocol
-            headers = req.headers_in.items()
-            rfile = _ReadOnlyRequest(req)
-            prev = None
-            
-            try:
-                redirections = []
-                while True:
-                    request, response = app.get_serving(local, remote, scheme,
-                                                        "HTTP/1.1")
-                    request.login = req.user
-                    request.multithread = bool(threaded)
-                    request.multiprocess = bool(forked)
-                    request.app = app
-                    request.prev = prev
-                    
-                    # Run the CherryPy Request object and obtain the response
-                    try:
-                        request.run(method, path, qs, reqproto, headers, rfile)
-                        break
-                    except cherrypy.InternalRedirect, ir:
-                        app.release_serving()
-                        prev = request
-                        
-                        if not recursive:
-                            if ir.path in redirections:
-                                raise RuntimeError("InternalRedirector visited the "
-                                                   "same URL twice: %r" % ir.path)
-                            else:
-                                # Add the *previous* path_info + qs to redirections.
-                                if qs:
-                                    qs = "?" + qs
-                                redirections.append(sn + path + qs)
-                        
-                        # Munge environment and try again.
-                        method = "GET"
-                        path = ir.path
-                        qs = ir.query_string
-                        rfile = StringIO()
-                
-                send_response(req, response.status, response.header_list,
-                              response.body, response.stream)
-            finally:
-                app.release_serving()
-    except:
-        tb = format_exc()
-        cherrypy.log(tb, 'MOD_PYTHON', severity=logging.ERROR)
-        s, h, b = bare_error()
-        send_response(req, s, h, b)
-    return apache.OK
-
-
-def send_response(req, status, headers, body, stream=False):
-    # Set response status
-    req.status = int(status[:3])
-    
-    # Set response headers
-    req.content_type = "text/plain"
-    for header, value in headers:
-        if header.lower() == 'content-type':
-            req.content_type = value
-            continue
-        req.headers_out.add(header, value)
-    
-    if stream:
-        # Flush now so the status and headers are sent immediately.
-        req.flush()
-    
-    # Set response body
-    if isinstance(body, basestring):
-        req.write(body)
-    else:
-        for seg in body:
-            req.write(seg)
-
-
-
-# --------------- Startup tools for CherryPy + mod_python --------------- #
-
-
-import os
-import re
-
-
-def read_process(cmd, args=""):
-    pipein, pipeout = os.popen4("%s %s" % (cmd, args))
-    try:
-        firstline = pipeout.readline()
-        if (re.search(r"(not recognized|No such file|not found)", firstline,
-                      re.IGNORECASE)):
-            raise IOError('%s must be on your system path.' % cmd)
-        output = firstline + pipeout.read()
-    finally:
-        pipeout.close()
-    return output
-
-
-class ModPythonServer(object):
-    
-    template = """
-# Apache2 server configuration file for running CherryPy with mod_python.
-
-DocumentRoot "/"
-Listen %(port)s
-LoadModule python_module modules/mod_python.so
-
-<Location %(loc)s>
-    SetHandler python-program
-    PythonHandler %(handler)s
-    PythonDebug On
-%(opts)s
-</Location>
-"""
-    
-    def __init__(self, loc="/", port=80, opts=None, apache_path="apache",
-                 handler="cherrypy._cpmodpy::handler"):
-        self.loc = loc
-        self.port = port
-        self.opts = opts
-        self.apache_path = apache_path
-        self.handler = handler
-    
-    def start(self):
-        opts = "".join(["    PythonOption %s %s\n" % (k, v)
-                        for k, v in self.opts])
-        conf_data = self.template % {"port": self.port,
-                                     "loc": self.loc,
-                                     "opts": opts,
-                                     "handler": self.handler,
-                                     }
-        
-        mpconf = os.path.join(os.path.dirname(__file__), "cpmodpy.conf")
-        f = open(mpconf, 'wb')
-        try:
-            f.write(conf_data)
-        finally:
-            f.close()
-        
-        response = read_process(self.apache_path, "-k start -f %s" % mpconf)
-        self.ready = True
-        return response
-    
-    def stop(self):
-        os.popen("apache -k stop")
-        self.ready = False
-
--- a/bundled/cherrypy/cherrypy/_cpnative_server.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,150 +0,0 @@
-"""Native adapter for serving CherryPy via its builtin server."""
-
-import logging
-try:
-    from cStringIO import StringIO
-except ImportError:
-    from StringIO import StringIO
-
-import cherrypy
-from cherrypy._cperror import format_exc, bare_error
-from cherrypy.lib import httputil
-from cherrypy import wsgiserver
-
-
-class NativeGateway(wsgiserver.Gateway):
-    
-    recursive = False
-    
-    def respond(self):
-        req = self.req
-        try:
-            # Obtain a Request object from CherryPy
-            local = req.server.bind_addr
-            local = httputil.Host(local[0], local[1], "")
-            remote = req.conn.remote_addr, req.conn.remote_port
-            remote = httputil.Host(remote[0], remote[1], "")
-            
-            scheme = req.scheme
-            sn = cherrypy.tree.script_name(req.uri or "/")
-            if sn is None:
-                self.send_response('404 Not Found', [], [''])
-            else:
-                app = cherrypy.tree.apps[sn]
-                method = req.method
-                path = req.path
-                qs = req.qs or ""
-                headers = req.inheaders.items()
-                rfile = req.rfile
-                prev = None
-                
-                try:
-                    redirections = []
-                    while True:
-                        request, response = app.get_serving(
-                            local, remote, scheme, "HTTP/1.1")
-                        request.multithread = True
-                        request.multiprocess = False
-                        request.app = app
-                        request.prev = prev
-                        
-                        # Run the CherryPy Request object and obtain the response
-                        try:
-                            request.run(method, path, qs, req.request_protocol, headers, rfile)
-                            break
-                        except cherrypy.InternalRedirect, ir:
-                            app.release_serving()
-                            prev = request
-                            
-                            if not self.recursive:
-                                if ir.path in redirections:
-                                    raise RuntimeError("InternalRedirector visited the "
-                                                       "same URL twice: %r" % ir.path)
-                                else:
-                                    # Add the *previous* path_info + qs to redirections.
-                                    if qs:
-                                        qs = "?" + qs
-                                    redirections.append(sn + path + qs)
-                            
-                            # Munge environment and try again.
-                            method = "GET"
-                            path = ir.path
-                            qs = ir.query_string
-                            rfile = StringIO()
-                    
-                    self.send_response(
-                        response.output_status, response.header_list,
-                        response.body)
-                finally:
-                    app.release_serving()
-        except:
-            tb = format_exc()
-            #print tb
-            cherrypy.log(tb, 'NATIVE_ADAPTER', severity=logging.ERROR)
-            s, h, b = bare_error()
-            self.send_response(s, h, b)
-    
-    def send_response(self, status, headers, body):
-        req = self.req
-        
-        # Set response status
-        req.status = str(status or "500 Server Error")
-        
-        # Set response headers
-        for header, value in headers:
-            req.outheaders.append((header, value))
-        if (req.ready and not req.sent_headers):
-            req.sent_headers = True
-            req.send_headers()
-        
-        # Set response body
-        for seg in body:
-            req.write(seg)
-
-
-class CPHTTPServer(wsgiserver.HTTPServer):
-    """Wrapper for wsgiserver.HTTPServer.
-    
-    wsgiserver has been designed to not reference CherryPy in any way,
-    so that it can be used in other frameworks and applications.
-    Therefore, we wrap it here, so we can apply some attributes
-    from config -> cherrypy.server -> HTTPServer.
-    """
-    
-    def __init__(self, server_adapter=cherrypy.server):
-        self.server_adapter = server_adapter
-        
-        server_name = (self.server_adapter.socket_host or
-                       self.server_adapter.socket_file or
-                       None)
-        
-        wsgiserver.HTTPServer.__init__(
-            self, server_adapter.bind_addr, NativeGateway,
-            minthreads=server_adapter.thread_pool,
-            maxthreads=server_adapter.thread_pool_max,
-            server_name=server_name)
-        
-        self.max_request_header_size = self.server_adapter.max_request_header_size or 0
-        self.max_request_body_size = self.server_adapter.max_request_body_size or 0
-        self.request_queue_size = self.server_adapter.socket_queue_size
-        self.timeout = self.server_adapter.socket_timeout
-        self.shutdown_timeout = self.server_adapter.shutdown_timeout
-        self.protocol = self.server_adapter.protocol_version
-        self.nodelay = self.server_adapter.nodelay
-        
-        ssl_module = self.server_adapter.ssl_module or 'pyopenssl'
-        if self.server_adapter.ssl_context:
-            adapter_class = wsgiserver.get_ssl_adapter_class(ssl_module)
-            self.ssl_adapter = adapter_class(
-                self.server_adapter.ssl_certificate,
-                self.server_adapter.ssl_private_key,
-                self.server_adapter.ssl_certificate_chain)
-            self.ssl_adapter.context = self.server_adapter.ssl_context
-        elif self.server_adapter.ssl_certificate:
-            adapter_class = wsgiserver.get_ssl_adapter_class(ssl_module)
-            self.ssl_adapter = adapter_class(
-                self.server_adapter.ssl_certificate,
-                self.server_adapter.ssl_private_key,
-                self.server_adapter.ssl_certificate_chain)
-
-
--- a/bundled/cherrypy/cherrypy/_cpreqbody.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,723 +0,0 @@
-"""Request body processing for CherryPy.
-
-When an HTTP request includes an entity body, it is often desirable to
-provide that information to applications in a form other than the raw bytes.
-Different content types demand different approaches. Examples:
-
- * For a GIF file, we want the raw bytes in a stream.
- * An HTML form is better parsed into its component fields, and each text field
-    decoded from bytes to unicode.
- * A JSON body should be deserialized into a Python dict or list.
-
-When the request contains a Content-Type header, the media type is used as a
-key to look up a value in the 'request.body.processors' dict. If the full media
-type is not found, then the major type is tried; for example, if no processor
-is found for the 'image/jpeg' type, then we look for a processor for the 'image'
-types altogether. If neither the full type nor the major type has a matching
-processor, then a default processor is used (self.default_proc). For most
-types, this means no processing is done, and the body is left unread as a
-raw byte stream. Processors are configurable in an 'on_start_resource' hook.
-
-Some processors, especially those for the 'text' types, attempt to decode bytes
-to unicode. If the Content-Type request header includes a 'charset' parameter,
-this is used to decode the entity. Otherwise, one or more default charsets may
-be attempted, although this decision is up to each processor. If a processor
-successfully decodes an Entity or Part, it should set the 'charset' attribute
-on the Entity or Part to the name of the successful charset, so that
-applications can easily re-encode or transcode the value if they wish.
-
-If the Content-Type of the request entity is of major type 'multipart', then
-the above parsing process, and possibly a decoding process, is performed for
-each part.
-
-For both the full entity and multipart parts, a Content-Disposition header may
-be used to fill .name and .filename attributes on the request.body or the Part.
-"""
-
-import re
-import tempfile
-from urllib import unquote_plus
-
-import cherrypy
-from cherrypy.lib import httputil
-
-
-# -------------------------------- Processors -------------------------------- #
-
-def process_urlencoded(entity):
-    """Read application/x-www-form-urlencoded data into entity.params."""
-    qs = entity.fp.read()
-    for charset in entity.attempt_charsets:
-        try:
-            params = {}
-            for aparam in qs.split('&'):
-                for pair in aparam.split(';'):
-                    if not pair:
-                        continue
-                    
-                    atoms = pair.split('=', 1)
-                    if len(atoms) == 1:
-                        atoms.append('')
-                    
-                    key = unquote_plus(atoms[0]).decode(charset)
-                    value = unquote_plus(atoms[1]).decode(charset)
-                    
-                    if key in params:
-                        if not isinstance(params[key], list):
-                            params[key] = [params[key]]
-                        params[key].append(value)
-                    else:
-                        params[key] = value
-        except UnicodeDecodeError:
-            pass
-        else:
-            entity.charset = charset
-            break
-    else:
-        raise cherrypy.HTTPError(
-            400, "The request entity could not be decoded. The following "
-            "charsets were attempted: %s" % repr(entity.attempt_charsets))
-        
-    # Now that all values have been successfully parsed and decoded,
-    # apply them to the entity.params dict.
-    for key, value in params.items():
-        if key in entity.params:
-            if not isinstance(entity.params[key], list):
-                entity.params[key] = [entity.params[key]]
-            entity.params[key].append(value)
-        else:
-            entity.params[key] = value
-
-
-def process_multipart(entity):
-    """Read all multipart parts into entity.parts."""
-    ib = u""
-    if u'boundary' in entity.content_type.params:
-        # http://tools.ietf.org/html/rfc2046#section-5.1.1
-        # "The grammar for parameters on the Content-type field is such that it
-        # is often necessary to enclose the boundary parameter values in quotes
-        # on the Content-type line"
-        ib = entity.content_type.params['boundary'].strip(u'"')
-    
-    if not re.match(u"^[ -~]{0,200}[!-~]$", ib):
-        raise ValueError(u'Invalid boundary in multipart form: %r' % (ib,))
-    
-    ib = (u'--' + ib).encode('ascii')
-    
-    # Find the first marker
-    while True:
-        b = entity.readline()
-        if not b:
-            return
-        
-        b = b.strip()
-        if b == ib:
-            break
-    
-    # Read all parts
-    while True:
-        part = entity.part_class.from_fp(entity.fp, ib)
-        entity.parts.append(part)
-        part.process()
-        if part.fp.done:
-            break
-
-def process_multipart_form_data(entity):
-    """Read all multipart/form-data parts into entity.parts or entity.params."""
-    process_multipart(entity)
-    
-    kept_parts = []
-    for part in entity.parts:
-        if part.name is None:
-            kept_parts.append(part)
-        else:
-            if part.filename is None:
-                # It's a regular field
-                entity.params[part.name] = part.fullvalue()
-            else:
-                # It's a file upload. Retain the whole part so consumer code
-                # has access to its .file and .filename attributes.
-                entity.params[part.name] = part
-    
-    entity.parts = kept_parts
-
-def _old_process_multipart(entity):
-    """The behavior of 3.2 and lower. Deprecated and will be changed in 3.3."""
-    process_multipart(entity)
-    
-    params = entity.params
-    
-    for part in entity.parts:
-        if part.name is None:
-            key = u'parts'
-        else:
-            key = part.name
-        
-        if part.filename is None:
-            # It's a regular field
-            value = part.fullvalue()
-        else:
-            # It's a file upload. Retain the whole part so consumer code
-            # has access to its .file and .filename attributes.
-            value = part
-        
-        if key in params:
-            if not isinstance(params[key], list):
-                params[key] = [params[key]]
-            params[key].append(value)
-        else:
-            params[key] = value
-
-
-
-# --------------------------------- Entities --------------------------------- #
-
-
-class Entity(object):
-    """An HTTP request body, or MIME multipart body."""
-    
-    __metaclass__ = cherrypy._AttributeDocstrings
-    
-    params = None
-    params__doc = u"""
-    If the request Content-Type is 'application/x-www-form-urlencoded' or
-    multipart, this will be a dict of the params pulled from the entity
-    body; that is, it will be the portion of request.params that come
-    from the message body (sometimes called "POST params", although they
-    can be sent with various HTTP method verbs). This value is set between
-    the 'before_request_body' and 'before_handler' hooks (assuming that
-    process_request_body is True)."""
-    
-    default_content_type = u'application/x-www-form-urlencoded'
-    # http://tools.ietf.org/html/rfc2046#section-4.1.2:
-    # "The default character set, which must be assumed in the
-    # absence of a charset parameter, is US-ASCII."
-    # However, many browsers send data in utf-8 with no charset.
-    attempt_charsets = [u'utf-8']
-    processors = {u'application/x-www-form-urlencoded': process_urlencoded,
-                  u'multipart/form-data': process_multipart_form_data,
-                  u'multipart': process_multipart,
-                  }
-    
-    def __init__(self, fp, headers, params=None, parts=None):
-        # Make an instance-specific copy of the class processors
-        # so Tools, etc. can replace them per-request.
-        self.processors = self.processors.copy()
-        
-        self.fp = fp
-        self.headers = headers
-        
-        if params is None:
-            params = {}
-        self.params = params
-        
-        if parts is None:
-            parts = []
-        self.parts = parts
-        
-        # Content-Type
-        self.content_type = headers.elements(u'Content-Type')
-        if self.content_type:
-            self.content_type = self.content_type[0]
-        else:
-            self.content_type = httputil.HeaderElement.from_str(
-                self.default_content_type)
-        
-        # Copy the class 'attempt_charsets', prepending any Content-Type charset
-        dec = self.content_type.params.get(u"charset", None)
-        if dec:
-            dec = dec.decode('ISO-8859-1')
-            self.attempt_charsets = [dec] + [c for c in self.attempt_charsets
-                                             if c != dec]
-        else:
-            self.attempt_charsets = self.attempt_charsets[:]
-        
-        # Length
-        self.length = None
-        clen = headers.get(u'Content-Length', None)
-        # If Transfer-Encoding is 'chunked', ignore any Content-Length.
-        if clen is not None and 'chunked' not in headers.get(u'Transfer-Encoding', ''):
-            try:
-                self.length = int(clen)
-            except ValueError:
-                pass
-        
-        # Content-Disposition
-        self.name = None
-        self.filename = None
-        disp = headers.elements(u'Content-Disposition')
-        if disp:
-            disp = disp[0]
-            if 'name' in disp.params:
-                self.name = disp.params['name']
-                if self.name.startswith(u'"') and self.name.endswith(u'"'):
-                    self.name = self.name[1:-1]
-            if 'filename' in disp.params:
-                self.filename = disp.params['filename']
-                if self.filename.startswith(u'"') and self.filename.endswith(u'"'):
-                    self.filename = self.filename[1:-1]
-    
-    # The 'type' attribute is deprecated in 3.2; remove it in 3.3.
-    type = property(lambda self: self.content_type)
-    
-    def read(self, size=None, fp_out=None):
-        return self.fp.read(size, fp_out)
-    
-    def readline(self, size=None):
-        return self.fp.readline(size)
-    
-    def readlines(self, sizehint=None):
-        return self.fp.readlines(sizehint)
-    
-    def __iter__(self):
-        return self
-    
-    def next(self):
-        line = self.readline()
-        if not line:
-            raise StopIteration
-        return line
-    
-    def read_into_file(self, fp_out=None):
-        """Read the request body into fp_out (or make_file() if None). Return fp_out."""
-        if fp_out is None:
-            fp_out = self.make_file()
-        self.read(fp_out=fp_out)
-        return fp_out
-    
-    def make_file(self):
-        """Return a file into which the request body will be read.
-        
-        By default, this will return a TemporaryFile. Override as needed."""
-        return tempfile.TemporaryFile()
-    
-    def fullvalue(self):
-        """Return this entity as a string, whether stored in a file or not."""
-        if self.file:
-            # It was stored in a tempfile. Read it.
-            self.file.seek(0)
-            value = self.file.read()
-            self.file.seek(0)
-        else:
-            value = self.value
-        return value
-    
-    def process(self):
-        """Execute the best-match processor for the given media type."""
-        proc = None
-        ct = self.content_type.value
-        try:
-            proc = self.processors[ct]
-        except KeyError:
-            toptype = ct.split(u'/', 1)[0]
-            try:
-                proc = self.processors[toptype]
-            except KeyError:
-                pass
-        if proc is None:
-            self.default_proc()
-        else:
-            proc(self)
-    
-    def default_proc(self):
-        # Leave the fp alone for someone else to read. This works fine
-        # for request.body, but the Part subclasses need to override this
-        # so they can move on to the next part.
-        pass
-
-
-class Part(Entity):
-    """A MIME part entity, part of a multipart entity."""
-    
-    default_content_type = u'text/plain'
-    # "The default character set, which must be assumed in the absence of a
-    # charset parameter, is US-ASCII."
-    attempt_charsets = [u'us-ascii', u'utf-8']
-    # This is the default in stdlib cgi. We may want to increase it.
-    maxrambytes = 1000
-    
-    def __init__(self, fp, headers, boundary):
-        Entity.__init__(self, fp, headers)
-        self.boundary = boundary
-        self.file = None
-        self.value = None
-    
-    def from_fp(cls, fp, boundary):
-        headers = cls.read_headers(fp)
-        return cls(fp, headers, boundary)
-    from_fp = classmethod(from_fp)
-    
-    def read_headers(cls, fp):
-        headers = httputil.HeaderMap()
-        while True:
-            line = fp.readline()
-            if not line:
-                # No more data--illegal end of headers
-                raise EOFError(u"Illegal end of headers.")
-            
-            if line == '\r\n':
-                # Normal end of headers
-                break
-            if not line.endswith('\r\n'):
-                raise ValueError(u"MIME requires CRLF terminators: %r" % line)
-            
-            if line[0] in ' \t':
-                # It's a continuation line.
-                v = line.strip().decode(u'ISO-8859-1')
-            else:
-                k, v = line.split(":", 1)
-                k = k.strip().decode(u'ISO-8859-1')
-                v = v.strip().decode(u'ISO-8859-1')
-            
-            existing = headers.get(k)
-            if existing:
-                v = u", ".join((existing, v))
-            headers[k] = v
-        
-        return headers
-    read_headers = classmethod(read_headers)
-    
-    def read_lines_to_boundary(self, fp_out=None):
-        """Read bytes from self.fp and return or write them to a file.
-        
-        If the 'fp_out' argument is None (the default), all bytes read are
-        returned in a single byte string.
-        
-        If the 'fp_out' argument is not None, it must be a file-like object that
-        supports the 'write' method; all bytes read will be written to the fp,
-        and that fp is returned.
-        """
-        endmarker = self.boundary + "--"
-        delim = ""
-        prev_lf = True
-        lines = []
-        seen = 0
-        while True:
-            line = self.fp.readline(1<<16)
-            if not line:
-                raise EOFError(u"Illegal end of multipart body.")
-            if line.startswith("--") and prev_lf:
-                strippedline = line.strip()
-                if strippedline == self.boundary:
-                    break
-                if strippedline == endmarker:
-                    self.fp.finish()
-                    break
-            
-            line = delim + line
-            
-            if line.endswith("\r\n"):
-                delim = "\r\n"
-                line = line[:-2]
-                prev_lf = True
-            elif line.endswith("\n"):
-                delim = "\n"
-                line = line[:-1]
-                prev_lf = True
-            else:
-                delim = ""
-                prev_lf = False
-            
-            if fp_out is None:
-                lines.append(line)
-                seen += len(line)
-                if seen > self.maxrambytes:
-                    fp_out = self.make_file()
-                    for line in lines:
-                        fp_out.write(line)
-            else:
-                fp_out.write(line)
-        
-        if fp_out is None:
-            result = ''.join(lines)
-            for charset in self.attempt_charsets:
-                try:
-                    result = result.decode(charset)
-                except UnicodeDecodeError:
-                    pass
-                else:
-                    self.charset = charset
-                    return result
-            else:
-                raise cherrypy.HTTPError(
-                    400, "The request entity could not be decoded. The following "
-                    "charsets were attempted: %s" % repr(self.attempt_charsets))
-        else:
-            fp_out.seek(0)
-            return fp_out
-    
-    def default_proc(self):
-        if self.filename:
-            # Always read into a file if a .filename was given.
-            self.file = self.read_into_file()
-        else:
-            result = self.read_lines_to_boundary()
-            if isinstance(result, basestring):
-                self.value = result
-            else:
-                self.file = result
-    
-    def read_into_file(self, fp_out=None):
-        """Read the request body into fp_out (or make_file() if None). Return fp_out."""
-        if fp_out is None:
-            fp_out = self.make_file()
-        self.read_lines_to_boundary(fp_out=fp_out)
-        return fp_out
-
-Entity.part_class = Part
-
-
-class Infinity(object):
-    def __cmp__(self, other):
-        return 1
-    def __sub__(self, other):
-        return self
-inf = Infinity()
-
-
-comma_separated_headers = ['Accept', 'Accept-Charset', 'Accept-Encoding',
-    'Accept-Language', 'Accept-Ranges', 'Allow', 'Cache-Control', 'Connection',
-    'Content-Encoding', 'Content-Language', 'Expect', 'If-Match',
-    'If-None-Match', 'Pragma', 'Proxy-Authenticate', 'Te', 'Trailer',
-    'Transfer-Encoding', 'Upgrade', 'Vary', 'Via', 'Warning', 'Www-Authenticate']
-
-
-class SizedReader:
-    
-    def __init__(self, fp, length, maxbytes, bufsize=8192, has_trailers=False):
-        # Wrap our fp in a buffer so peek() works
-        self.fp = fp
-        self.length = length
-        self.maxbytes = maxbytes
-        self.buffer = ''
-        self.bufsize = bufsize
-        self.bytes_read = 0
-        self.done = False
-        self.has_trailers = has_trailers
-    
-    def read(self, size=None, fp_out=None):
-        """Read bytes from the request body and return or write them to a file.
-        
-        A number of bytes less than or equal to the 'size' argument are read
-        off the socket. The actual number of bytes read are tracked in
-        self.bytes_read. The number may be smaller than 'size' when 1) the
-        client sends fewer bytes, 2) the 'Content-Length' request header
-        specifies fewer bytes than requested, or 3) the number of bytes read
-        exceeds self.maxbytes (in which case, 413 is raised).
-        
-        If the 'fp_out' argument is None (the default), all bytes read are
-        returned in a single byte string.
-        
-        If the 'fp_out' argument is not None, it must be a file-like object that
-        supports the 'write' method; all bytes read will be written to the fp,
-        and None is returned.
-        """
-        
-        if self.length is None:
-            if size is None:
-                remaining = inf
-            else:
-                remaining = size
-        else:
-            remaining = self.length - self.bytes_read
-            if size and size < remaining:
-                remaining = size
-        if remaining == 0:
-            self.finish()
-            if fp_out is None:
-                return ''
-            else:
-                return None
-        
-        chunks = []
-        
-        # Read bytes from the buffer.
-        if self.buffer:
-            if remaining is inf:
-                data = self.buffer
-                self.buffer = ''
-            else:
-                data = self.buffer[:remaining]
-                self.buffer = self.buffer[remaining:]
-            datalen = len(data)
-            remaining -= datalen
-            
-            # Check lengths.
-            self.bytes_read += datalen
-            if self.maxbytes and self.bytes_read > self.maxbytes:
-                raise cherrypy.HTTPError(413)
-            
-            # Store the data.
-            if fp_out is None:
-                chunks.append(data)
-            else:
-                fp_out.write(data)
-        
-        # Read bytes from the socket.
-        while remaining > 0:
-            chunksize = min(remaining, self.bufsize)
-            try:
-                data = self.fp.read(chunksize)
-            except Exception, e:
-                if e.__class__.__name__ == 'MaxSizeExceeded':
-                    # Post data is too big
-                    raise cherrypy.HTTPError(
-                        413, "Maximum request length: %r" % e.args[1])
-                else:
-                    raise
-            if not data:
-                self.finish()
-                break
-            datalen = len(data)
-            remaining -= datalen
-            
-            # Check lengths.
-            self.bytes_read += datalen
-            if self.maxbytes and self.bytes_read > self.maxbytes:
-                raise cherrypy.HTTPError(413)
-            
-            # Store the data.
-            if fp_out is None:
-                chunks.append(data)
-            else:
-                fp_out.write(data)
-        
-        if fp_out is None:
-            return ''.join(chunks)
-    
-    def readline(self, size=None):
-        """Read a line from the request body and return it."""
-        chunks = []
-        while size is None or size > 0:
-            chunksize = self.bufsize
-            if size is not None and size < self.bufsize:
-                chunksize = size
-            data = self.read(chunksize)
-            if not data:
-                break
-            pos = data.find('\n') + 1
-            if pos:
-                chunks.append(data[:pos])
-                remainder = data[pos:]
-                self.buffer += remainder
-                self.bytes_read -= len(remainder)
-                break
-            else:
-                chunks.append(data)
-        return ''.join(chunks)
-    
-    def readlines(self, sizehint=None):
-        """Read lines from the request body and return them."""
-        if self.length is not None:
-            if sizehint is None:
-                sizehint = self.length - self.bytes_read
-            else:
-                sizehint = min(sizehint, self.length - self.bytes_read)
-        
-        lines = []
-        seen = 0
-        while True:
-            line = self.readline()
-            if not line:
-                break
-            lines.append(line)
-            seen += len(line)
-            if seen >= sizehint:
-                break
-        return lines
-    
-    def finish(self):
-        self.done = True
-        if self.has_trailers and hasattr(self.fp, 'read_trailer_lines'):
-            self.trailers = {}
-            
-            try:
-                for line in self.fp.read_trailer_lines():
-                    if line[0] in ' \t':
-                        # It's a continuation line.
-                        v = line.strip()
-                    else:
-                        try:
-                            k, v = line.split(":", 1)
-                        except ValueError:
-                            raise ValueError("Illegal header line.")
-                        k = k.strip().title()
-                        v = v.strip()
-                    
-                    if k in comma_separated_headers:
-                        existing = self.trailers.get(envname)
-                        if existing:
-                            v = ", ".join((existing, v))
-                    self.trailers[k] = v
-            except Exception, e:
-                if e.__class__.__name__ == 'MaxSizeExceeded':
-                    # Post data is too big
-                    raise cherrypy.HTTPError(
-                        413, "Maximum request length: %r" % e.args[1])
-                else:
-                    raise
-
-
-class RequestBody(Entity):
-    
-    # Don't parse the request body at all if the client didn't provide
-    # a Content-Type header. See http://www.cherrypy.org/ticket/790
-    default_content_type = u''
-    
-    bufsize = 8 * 1024
-    maxbytes = None
-    
-    def __init__(self, fp, headers, params=None, request_params=None):
-        Entity.__init__(self, fp, headers, params)
-        
-        # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7.1
-        # When no explicit charset parameter is provided by the
-        # sender, media subtypes of the "text" type are defined
-        # to have a default charset value of "ISO-8859-1" when
-        # received via HTTP.
-        if self.content_type.value.startswith('text/'):
-            for c in (u'ISO-8859-1', u'iso-8859-1', u'Latin-1', u'latin-1'):
-                if c in self.attempt_charsets:
-                    break
-            else:
-                self.attempt_charsets.append(u'ISO-8859-1')
-        
-        # Temporary fix while deprecating passing .parts as .params.
-        self.processors[u'multipart'] = _old_process_multipart
-        
-        if request_params is None:
-            request_params = {}
-        self.request_params = request_params
-    
-    def process(self):
-        """Include body params in request params."""
-        # "The presence of a message-body in a request is signaled by the
-        # inclusion of a Content-Length or Transfer-Encoding header field in
-        # the request's message-headers."
-        # It is possible to send a POST request with no body, for example;
-        # however, app developers are responsible in that case to set
-        # cherrypy.request.process_body to False so this method isn't called.
-        h = cherrypy.serving.request.headers
-        if u'Content-Length' not in h and u'Transfer-Encoding' not in h:
-            raise cherrypy.HTTPError(411)
-        
-        self.fp = SizedReader(self.fp, self.length,
-                              self.maxbytes, bufsize=self.bufsize,
-                              has_trailers='Trailer' in h)
-        super(RequestBody, self).process()
-        
-        # Body params should also be a part of the request_params
-        # add them in here.
-        request_params = self.request_params
-        for key, value in self.params.items():
-            # Python 2 only: keyword arguments must be byte strings (type 'str').
-            if isinstance(key, unicode):
-                key = key.encode('ISO-8859-1')
-            
-            if key in request_params:
-                if not isinstance(request_params[key], list):
-                    request_params[key] = [request_params[key]]
-                request_params[key].append(value)
-            else:
-                request_params[key] = value
-
--- a/bundled/cherrypy/cherrypy/_cprequest.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,940 +0,0 @@
-
-from Cookie import SimpleCookie, CookieError
-import os
-import sys
-import time
-import types
-import warnings
-
-import cherrypy
-from cherrypy import _cpreqbody, _cpconfig
-from cherrypy._cperror import format_exc, bare_error
-from cherrypy.lib import httputil, file_generator
-
-
-class Hook(object):
-    """A callback and its metadata: failsafe, priority, and kwargs."""
-    
-    __metaclass__ = cherrypy._AttributeDocstrings
-    
-    callback = None
-    callback__doc = """
-    The bare callable that this Hook object is wrapping, which will
-    be called when the Hook is called."""
-    
-    failsafe = False
-    failsafe__doc = """
-    If True, the callback is guaranteed to run even if other callbacks
-    from the same call point raise exceptions."""
-    
-    priority = 50
-    priority__doc = """
-    Defines the order of execution for a list of Hooks. Priority numbers
-    should be limited to the closed interval [0, 100], but values outside
-    this range are acceptable, as are fractional values."""
-    
-    kwargs = {}
-    kwargs__doc = """
-    A set of keyword arguments that will be passed to the
-    callable on each call."""
-    
-    def __init__(self, callback, failsafe=None, priority=None, **kwargs):
-        self.callback = callback
-        
-        if failsafe is None:
-            failsafe = getattr(callback, "failsafe", False)
-        self.failsafe = failsafe
-        
-        if priority is None:
-            priority = getattr(callback, "priority", 50)
-        self.priority = priority
-        
-        self.kwargs = kwargs
-    
-    def __cmp__(self, other):
-        return cmp(self.priority, other.priority)
-    
-    def __call__(self):
-        """Run self.callback(**self.kwargs)."""
-        return self.callback(**self.kwargs)
-    
-    def __repr__(self):
-        cls = self.__class__
-        return ("%s.%s(callback=%r, failsafe=%r, priority=%r, %s)"
-                % (cls.__module__, cls.__name__, self.callback,
-                   self.failsafe, self.priority,
-                   ", ".join(['%s=%r' % (k, v)
-                              for k, v in self.kwargs.items()])))
-
-
-class HookMap(dict):
-    """A map of call points to lists of callbacks (Hook objects)."""
-    
-    def __new__(cls, points=None):
-        d = dict.__new__(cls)
-        for p in points or []:
-            d[p] = []
-        return d
-    
-    def __init__(self, *a, **kw):
-        pass
-    
-    def attach(self, point, callback, failsafe=None, priority=None, **kwargs):
-        """Append a new Hook made from the supplied arguments."""
-        self[point].append(Hook(callback, failsafe, priority, **kwargs))
-    
-    def run(self, point):
-        """Execute all registered Hooks (callbacks) for the given point."""
-        exc = None
-        hooks = self[point]
-        hooks.sort()
-        for hook in hooks:
-            # Some hooks are guaranteed to run even if others at
-            # the same hookpoint fail. We will still log the failure,
-            # but proceed on to the next hook. The only way
-            # to stop all processing from one of these hooks is
-            # to raise SystemExit and stop the whole server.
-            if exc is None or hook.failsafe:
-                try:
-                    hook()
-                except (KeyboardInterrupt, SystemExit):
-                    raise
-                except (cherrypy.HTTPError, cherrypy.HTTPRedirect,
-                        cherrypy.InternalRedirect):
-                    exc = sys.exc_info()[1]
-                except:
-                    exc = sys.exc_info()[1]
-                    cherrypy.log(traceback=True, severity=40)
-        if exc:
-            raise
-    
-    def __copy__(self):
-        newmap = self.__class__()
-        # We can't just use 'update' because we want copies of the
-        # mutable values (each is a list) as well.
-        for k, v in self.items():
-            newmap[k] = v[:]
-        return newmap
-    copy = __copy__
-    
-    def __repr__(self):
-        cls = self.__class__
-        return "%s.%s(points=%r)" % (cls.__module__, cls.__name__, self.keys())
-
-
-# Config namespace handlers
-
-def hooks_namespace(k, v):
-    """Attach bare hooks declared in config."""
-    # Use split again to allow multiple hooks for a single
-    # hookpoint per path (e.g. "hooks.before_handler.1").
-    # Little-known fact you only get from reading source ;)
-    hookpoint = k.split(".", 1)[0]
-    if isinstance(v, basestring):
-        v = cherrypy.lib.attributes(v)
-    if not isinstance(v, Hook):
-        v = Hook(v)
-    cherrypy.serving.request.hooks[hookpoint].append(v)
-
-def request_namespace(k, v):
-    """Attach request attributes declared in config."""
-    # Provides config entries to set request.body attrs (like attempt_charsets).
-    if k[:5] == 'body.':
-        setattr(cherrypy.serving.request.body, k[5:], v)
-    else:
-        setattr(cherrypy.serving.request, k, v)
-
-def response_namespace(k, v):
-    """Attach response attributes declared in config."""
-    # Provides config entries to set default response headers
-    # http://cherrypy.org/ticket/889
-    if k[:8] == 'headers.':
-        cherrypy.serving.response.headers[k.split('.', 1)[1]] = v
-    else:
-        setattr(cherrypy.serving.response, k, v)
-
-def error_page_namespace(k, v):
-    """Attach error pages declared in config."""
-    if k != 'default':
-        k = int(k)
-    cherrypy.serving.request.error_page[k] = v
-
-
-hookpoints = ['on_start_resource', 'before_request_body',
-              'before_handler', 'before_finalize',
-              'on_end_resource', 'on_end_request',
-              'before_error_response', 'after_error_response']
-
-
-class Request(object):
-    """An HTTP request.
-    
-    This object represents the metadata of an HTTP request message;
-    that is, it contains attributes which describe the environment
-    in which the request URL, headers, and body were sent (if you
-    want tools to interpret the headers and body, those are elsewhere,
-    mostly in Tools). This 'metadata' consists of socket data,
-    transport characteristics, and the Request-Line. This object
-    also contains data regarding the configuration in effect for
-    the given URL, and the execution plan for generating a response.
-    """
-    
-    __metaclass__ = cherrypy._AttributeDocstrings
-    
-    prev = None
-    prev__doc = """
-    The previous Request object (if any). This should be None
-    unless we are processing an InternalRedirect."""
-    
-    # Conversation/connection attributes
-    local = httputil.Host("127.0.0.1", 80)
-    local__doc = \
-        "An httputil.Host(ip, port, hostname) object for the server socket."
-    
-    remote = httputil.Host("127.0.0.1", 1111)
-    remote__doc = \
-        "An httputil.Host(ip, port, hostname) object for the client socket."
-    
-    scheme = "http"
-    scheme__doc = """
-    The protocol used between client and server. In most cases,
-    this will be either 'http' or 'https'."""
-    
-    server_protocol = "HTTP/1.1"
-    server_protocol__doc = """
-    The HTTP version for which the HTTP server is at least
-    conditionally compliant."""
-    
-    base = ""
-    base__doc = """The (scheme://host) portion of the requested URL.
-    In some cases (e.g. when proxying via mod_rewrite), this may contain
-    path segments which cherrypy.url uses when constructing url's, but
-    which otherwise are ignored by CherryPy. Regardless, this value
-    MUST NOT end in a slash."""
-    
-    # Request-Line attributes
-    request_line = ""
-    request_line__doc = """
-    The complete Request-Line received from the client. This is a
-    single string consisting of the request method, URI, and protocol
-    version (joined by spaces). Any final CRLF is removed."""
-    
-    method = "GET"
-    method__doc = """
-    Indicates the HTTP method to be performed on the resource identified
-    by the Request-URI. Common methods include GET, HEAD, POST, PUT, and
-    DELETE. CherryPy allows any extension method; however, various HTTP
-    servers and gateways may restrict the set of allowable methods.
-    CherryPy applications SHOULD restrict the set (on a per-URI basis)."""
-    
-    query_string = ""
-    query_string__doc = """
-    The query component of the Request-URI, a string of information to be
-    interpreted by the resource. The query portion of a URI follows the
-    path component, and is separated by a '?'. For example, the URI
-    'http://www.cherrypy.org/wiki?a=3&b=4' has the query component,
-    'a=3&b=4'."""
-    
-    query_string_encoding = 'utf8'
-    query_string_encoding__doc = """
-    The encoding expected for query string arguments after % HEX HEX decoding).
-    If a query string is provided that cannot be decoded with this encoding,
-    404 is raised (since technically it's a different URI). If you want
-    arbitrary encodings to not error, set this to 'Latin-1'; you can then
-    encode back to bytes and re-decode to whatever encoding you like later.
-    """
-    
-    protocol = (1, 1)
-    protocol__doc = """The HTTP protocol version corresponding to the set
-        of features which should be allowed in the response. If BOTH
-        the client's request message AND the server's level of HTTP
-        compliance is HTTP/1.1, this attribute will be the tuple (1, 1).
-        If either is 1.0, this attribute will be the tuple (1, 0).
-        Lower HTTP protocol versions are not explicitly supported."""
-    
-    params = {}
-    params__doc = """
-    A dict which combines query string (GET) and request entity (POST)
-    variables. This is populated in two stages: GET params are added
-    before the 'on_start_resource' hook, and POST params are added
-    between the 'before_request_body' and 'before_handler' hooks."""
-    
-    # Message attributes
-    header_list = []
-    header_list__doc = """
-    A list of the HTTP request headers as (name, value) tuples.
-    In general, you should use request.headers (a dict) instead."""
-    
-    headers = httputil.HeaderMap()
-    headers__doc = """
-    A dict-like object containing the request headers. Keys are header
-    names (in Title-Case format); however, you may get and set them in
-    a case-insensitive manner. That is, headers['Content-Type'] and
-    headers['content-type'] refer to the same value. Values are header
-    values (decoded according to RFC 2047 if necessary). See also:
-    httputil.HeaderMap, httputil.HeaderElement."""
-    
-    cookie = SimpleCookie()
-    cookie__doc = """See help(Cookie)."""
-    
-    body = None
-    body__doc = """See help(cherrypy.request.body)"""
-    
-    rfile = None
-    rfile__doc = """
-    If the request included an entity (body), it will be available
-    as a stream in this attribute. However, the rfile will normally
-    be read for you between the 'before_request_body' hook and the
-    'before_handler' hook, and the resulting string is placed into
-    either request.params or the request.body attribute.
-    
-    You may disable the automatic consumption of the rfile by setting
-    request.process_request_body to False, either in config for the desired
-    path, or in an 'on_start_resource' or 'before_request_body' hook.
-    
-    WARNING: In almost every case, you should not attempt to read from the
-    rfile stream after CherryPy's automatic mechanism has read it. If you
-    turn off the automatic parsing of rfile, you should read exactly the
-    number of bytes specified in request.headers['Content-Length'].
-    Ignoring either of these warnings may result in a hung request thread
-    or in corruption of the next (pipelined) request.
-    """
-    
-    process_request_body = True
-    process_request_body__doc = """
-    If True, the rfile (if any) is automatically read and parsed,
-    and the result placed into request.params or request.body."""
-    
-    methods_with_bodies = ("POST", "PUT")
-    methods_with_bodies__doc = """
-    A sequence of HTTP methods for which CherryPy will automatically
-    attempt to read a body from the rfile."""
-    
-    body = None
-    body__doc = """
-    If the request Content-Type is 'application/x-www-form-urlencoded'
-    or multipart, this will be None. Otherwise, this will contain the
-    request entity body as an open file object (which you can .read());
-    this value is set between the 'before_request_body' and 'before_handler'
-    hooks (assuming that process_request_body is True)."""
-    
-    body_params = None
-    body_params__doc = """
-    If the request Content-Type is 'application/x-www-form-urlencoded' or
-    multipart, this will be a dict of the params pulled from the entity
-    body; that is, it will be the portion of request.params that come
-    from the message body (sometimes called "POST params", although they
-    can be sent with various HTTP method verbs). This value is set between
-    the 'before_request_body' and 'before_handler' hooks (assuming that
-    process_request_body is True)."""
-    
-    # Dispatch attributes
-    dispatch = cherrypy.dispatch.Dispatcher()
-    dispatch__doc = """
-    The object which looks up the 'page handler' callable and collects
-    config for the current request based on the path_info, other
-    request attributes, and the application architecture. The core
-    calls the dispatcher as early as possible, passing it a 'path_info'
-    argument.
-    
-    The default dispatcher discovers the page handler by matching path_info
-    to a hierarchical arrangement of objects, starting at request.app.root.
-    See help(cherrypy.dispatch) for more information."""
-    
-    script_name = ""
-    script_name__doc = """
-    The 'mount point' of the application which is handling this request.
-    
-    This attribute MUST NOT end in a slash. If the script_name refers to
-    the root of the URI, it MUST be an empty string (not "/").
-    """
-    
-    path_info = "/"
-    path_info__doc = """
-    The 'relative path' portion of the Request-URI. This is relative
-    to the script_name ('mount point') of the application which is
-    handling this request."""
-
-    login = None
-    login__doc = """
-    When authentication is used during the request processing this is
-    set to 'False' if it failed and to the 'username' value if it succeeded.
-    The default 'None' implies that no authentication happened."""
-    
-    # Note that cherrypy.url uses "if request.app:" to determine whether
-    # the call is during a real HTTP request or not. So leave this None.
-    app = None
-    app__doc = \
-        """The cherrypy.Application object which is handling this request."""
-    
-    handler = None
-    handler__doc = """
-    The function, method, or other callable which CherryPy will call to
-    produce the response. The discovery of the handler and the arguments
-    it will receive are determined by the request.dispatch object.
-    By default, the handler is discovered by walking a tree of objects
-    starting at request.app.root, and is then passed all HTTP params
-    (from the query string and POST body) as keyword arguments."""
-    
-    toolmaps = {}
-    toolmaps__doc = """
-    A nested dict of all Toolboxes and Tools in effect for this request,
-    of the form: {Toolbox.namespace: {Tool.name: config dict}}."""
-    
-    config = None
-    config__doc = """
-    A flat dict of all configuration entries which apply to the
-    current request. These entries are collected from global config,
-    application config (based on request.path_info), and from handler
-    config (exactly how is governed by the request.dispatch object in
-    effect for this request; by default, handler config can be attached
-    anywhere in the tree between request.app.root and the final handler,
-    and inherits downward)."""
-    
-    is_index = None
-    is_index__doc = """
-    This will be True if the current request is mapped to an 'index'
-    resource handler (also, a 'default' handler if path_info ends with
-    a slash). The value may be used to automatically redirect the
-    user-agent to a 'more canonical' URL which either adds or removes
-    the trailing slash. See cherrypy.tools.trailing_slash."""
-    
-    hooks = HookMap(hookpoints)
-    hooks__doc = """
-    A HookMap (dict-like object) of the form: {hookpoint: [hook, ...]}.
-    Each key is a str naming the hook point, and each value is a list
-    of hooks which will be called at that hook point during this request.
-    The list of hooks is generally populated as early as possible (mostly
-    from Tools specified in config), but may be extended at any time.
-    See also: _cprequest.Hook, _cprequest.HookMap, and cherrypy.tools."""
-    
-    error_response = cherrypy.HTTPError(500).set_response
-    error_response__doc = """
-    The no-arg callable which will handle unexpected, untrapped errors
-    during request processing. This is not used for expected exceptions
-    (like NotFound, HTTPError, or HTTPRedirect) which are raised in
-    response to expected conditions (those should be customized either
-    via request.error_page or by overriding HTTPError.set_response).
-    By default, error_response uses HTTPError(500) to return a generic
-    error response to the user-agent."""
-    
-    error_page = {}
-    error_page__doc = """
-    A dict of {error code: response filename or callable} pairs.
-    
-    The error code must be an int representing a given HTTP error code,
-    or the string 'default', which will be used if no matching entry
-    is found for a given numeric code.
-    
-    If a filename is provided, the file should contain a Python string-
-    formatting template, and can expect by default to receive format 
-    values with the mapping keys %(status)s, %(message)s, %(traceback)s,
-    and %(version)s. The set of format mappings can be extended by
-    overriding HTTPError.set_response.
-    
-    If a callable is provided, it will be called by default with keyword
-    arguments 'status', 'message', 'traceback', and 'version', as for a
-    string-formatting template. The callable must return a string or iterable of
-    strings which will be set to response.body. It may also override headers or
-    perform any other processing.
-    
-    If no entry is given for an error code, and no 'default' entry exists,
-    a default template will be used.
-    """
-    
-    show_tracebacks = True
-    show_tracebacks__doc = """
-    If True, unexpected errors encountered during request processing will
-    include a traceback in the response body."""
-
-    show_mismatched_params = True
-    show_mismatched_params__doc = """
-    If True, mismatched parameters encountered during PageHandler invocation
-    processing will be included in the response body."""
-    
-    throws = (KeyboardInterrupt, SystemExit, cherrypy.InternalRedirect)
-    throws__doc = \
-        """The sequence of exceptions which Request.run does not trap."""
-    
-    throw_errors = False
-    throw_errors__doc = """
-    If True, Request.run will not trap any errors (except HTTPRedirect and
-    HTTPError, which are more properly called 'exceptions', not errors)."""
-    
-    closed = False
-    closed__doc = """
-    True once the close method has been called, False otherwise."""
-    
-    stage = None
-    stage__doc = """
-    A string containing the stage reached in the request-handling process.
-    This is useful when debugging a live server with hung requests."""
-    
-    namespaces = _cpconfig.NamespaceSet(
-        **{"hooks": hooks_namespace,
-           "request": request_namespace,
-           "response": response_namespace,
-           "error_page": error_page_namespace,
-           "tools": cherrypy.tools,
-           })
-    
-    def __init__(self, local_host, remote_host, scheme="http",
-                 server_protocol="HTTP/1.1"):
-        """Populate a new Request object.
-        
-        local_host should be an httputil.Host object with the server info.
-        remote_host should be an httputil.Host object with the client info.
-        scheme should be a string, either "http" or "https".
-        """
-        self.local = local_host
-        self.remote = remote_host
-        self.scheme = scheme
-        self.server_protocol = server_protocol
-        
-        self.closed = False
-        
-        # Put a *copy* of the class error_page into self.
-        self.error_page = self.error_page.copy()
-        
-        # Put a *copy* of the class namespaces into self.
-        self.namespaces = self.namespaces.copy()
-        
-        self.stage = None
-    
-    def close(self):
-        """Run cleanup code. (Core)"""
-        if not self.closed:
-            self.closed = True
-            self.stage = 'on_end_request'
-            self.hooks.run('on_end_request')
-            self.stage = 'close'
-    
-    def run(self, method, path, query_string, req_protocol, headers, rfile):
-        """Process the Request. (Core)
-        
-        method, path, query_string, and req_protocol should be pulled directly
-            from the Request-Line (e.g. "GET /path?key=val HTTP/1.0").
-        path should be %XX-unquoted, but query_string should not be.
-            They both MUST be byte strings, not unicode strings.
-        headers should be a list of (name, value) tuples.
-        rfile should be a file-like object containing the HTTP request entity.
-        
-        When run() is done, the returned object should have 3 attributes:
-          status, e.g. "200 OK"
-          header_list, a list of (name, value) tuples
-          body, an iterable yielding strings
-        
-        Consumer code (HTTP servers) should then access these response
-        attributes to build the outbound stream.
-        
-        """
-        response = cherrypy.serving.response
-        self.stage = 'run'
-        try:
-            self.error_response = cherrypy.HTTPError(500).set_response
-            
-            self.method = method
-            path = path or "/"
-            self.query_string = query_string or ''
-            self.params = {}
-            
-            # Compare request and server HTTP protocol versions, in case our
-            # server does not support the requested protocol. Limit our output
-            # to min(req, server). We want the following output:
-            #     request    server     actual written   supported response
-            #     protocol   protocol  response protocol    feature set
-            # a     1.0        1.0           1.0                1.0
-            # b     1.0        1.1           1.1                1.0
-            # c     1.1        1.0           1.0                1.0
-            # d     1.1        1.1           1.1                1.1
-            # Notice that, in (b), the response will be "HTTP/1.1" even though
-            # the client only understands 1.0. RFC 2616 10.5.6 says we should
-            # only return 505 if the _major_ version is different.
-            rp = int(req_protocol[5]), int(req_protocol[7])
-            sp = int(self.server_protocol[5]), int(self.server_protocol[7])
-            self.protocol = min(rp, sp)
-            response.headers.protocol = self.protocol
-            
-            # Rebuild first line of the request (e.g. "GET /path HTTP/1.0").
-            url = path
-            if query_string:
-                url += '?' + query_string
-            self.request_line = '%s %s %s' % (method, url, req_protocol)
-            
-            self.header_list = list(headers)
-            self.headers = httputil.HeaderMap()
-            
-            self.rfile = rfile
-            self.body = None
-            
-            self.cookie = SimpleCookie()
-            self.handler = None
-            
-            # path_info should be the path from the
-            # app root (script_name) to the handler.
-            self.script_name = self.app.script_name
-            self.path_info = pi = path[len(self.script_name):]
-            
-            self.stage = 'respond'
-            self.respond(pi)
-            
-        except self.throws:
-            raise
-        except:
-            if self.throw_errors:
-                raise
-            else:
-                # Failure in setup, error handler or finalize. Bypass them.
-                # Can't use handle_error because we may not have hooks yet.
-                cherrypy.log(traceback=True, severity=40)
-                if self.show_tracebacks:
-                    body = format_exc()
-                else:
-                    body = ""
-                r = bare_error(body)
-                response.output_status, response.header_list, response.body = r
-        
-        if self.method == "HEAD":
-            # HEAD requests MUST NOT return a message-body in the response.
-            response.body = []
-        
-        try:
-            cherrypy.log.access()
-        except:
-            cherrypy.log.error(traceback=True)
-        
-        if response.timed_out:
-            raise cherrypy.TimeoutError()
-        
-        return response
-    
-    # Uncomment for stage debugging
-    # stage = property(lambda self: self._stage, lambda self, v: print(v))
-    
-    def respond(self, path_info):
-        """Generate a response for the resource at self.path_info. (Core)"""
-        response = cherrypy.serving.response
-        try:
-            try:
-                try:
-                    if self.app is None:
-                        raise cherrypy.NotFound()
-                    
-                    # Get the 'Host' header, so we can HTTPRedirect properly.
-                    self.stage = 'process_headers'
-                    self.process_headers()
-                    
-                    # Make a copy of the class hooks
-                    self.hooks = self.__class__.hooks.copy()
-                    self.toolmaps = {}
-                    
-                    self.stage = 'get_resource'
-                    self.get_resource(path_info)
-                    
-                    self.body = _cpreqbody.RequestBody(
-                        self.rfile, self.headers, request_params=self.params)
-                    
-                    self.namespaces(self.config)
-                    
-                    self.stage = 'on_start_resource'
-                    self.hooks.run('on_start_resource')
-                    
-                    # Parse the querystring
-                    self.stage = 'process_query_string'
-                    self.process_query_string()
-                    
-                    # Process the body
-                    if self.process_request_body:
-                        if self.method not in self.methods_with_bodies:
-                            self.process_request_body = False
-                    self.stage = 'before_request_body'
-                    self.hooks.run('before_request_body')
-                    if self.process_request_body:
-                        self.body.process()
-                    
-                    # Run the handler
-                    self.stage = 'before_handler'
-                    self.hooks.run('before_handler')
-                    if self.handler:
-                        self.stage = 'handler'
-                        response.body = self.handler()
-                    
-                    # Finalize
-                    self.stage = 'before_finalize'
-                    self.hooks.run('before_finalize')
-                    response.finalize()
-                except (cherrypy.HTTPRedirect, cherrypy.HTTPError), inst:
-                    inst.set_response()
-                    self.stage = 'before_finalize (HTTPError)'
-                    self.hooks.run('before_finalize')
-                    response.finalize()
-            finally:
-                self.stage = 'on_end_resource'
-                self.hooks.run('on_end_resource')
-        except self.throws:
-            raise
-        except:
-            if self.throw_errors:
-                raise
-            self.handle_error()
-    
-    def process_query_string(self):
-        """Parse the query string into Python structures. (Core)"""
-        try:
-            p = httputil.parse_query_string(
-                self.query_string, encoding=self.query_string_encoding)
-        except UnicodeDecodeError:
-            raise cherrypy.HTTPError(
-                404, "The given query string could not be processed. Query "
-                "strings for this resource must be encoded with %r." %
-                self.query_string_encoding)
-        
-        # Python 2 only: keyword arguments must be byte strings (type 'str').
-        for key, value in p.items():
-            if isinstance(key, unicode):
-                del p[key]
-                p[key.encode(self.query_string_encoding)] = value
-        self.params.update(p)
-    
-    def process_headers(self):
-        """Parse HTTP header data into Python structures. (Core)"""
-        # Process the headers into self.headers
-        headers = self.headers
-        for name, value in self.header_list:
-            # Call title() now (and use dict.__method__(headers))
-            # so title doesn't have to be called twice.
-            name = name.title()
-            value = value.strip()
-            
-            # Warning: if there is more than one header entry for cookies (AFAIK,
-            # only Konqueror does that), only the last one will remain in headers
-            # (but they will be correctly stored in request.cookie).
-            if "=?" in value:
-                dict.__setitem__(headers, name, httputil.decode_TEXT(value))
-            else:
-                dict.__setitem__(headers, name, value)
-            
-            # Handle cookies differently because on Konqueror, multiple
-            # cookies come on different lines with the same key
-            if name == 'Cookie':
-                try:
-                    self.cookie.load(value)
-                except CookieError:
-                    msg = "Illegal cookie name %s" % value.split('=')[0]
-                    raise cherrypy.HTTPError(400, msg)
-        
-        if not dict.__contains__(headers, 'Host'):
-            # All Internet-based HTTP/1.1 servers MUST respond with a 400
-            # (Bad Request) status code to any HTTP/1.1 request message
-            # which lacks a Host header field.
-            if self.protocol >= (1, 1):
-                msg = "HTTP/1.1 requires a 'Host' request header."
-                raise cherrypy.HTTPError(400, msg)
-        host = dict.get(headers, 'Host')
-        if not host:
-            host = self.local.name or self.local.ip
-        self.base = "%s://%s" % (self.scheme, host)
-    
-    def get_resource(self, path):
-        """Call a dispatcher (which sets self.handler and .config). (Core)"""
-        # First, see if there is a custom dispatch at this URI. Custom
-        # dispatchers can only be specified in app.config, not in _cp_config
-        # (since custom dispatchers may not even have an app.root).
-        dispatch = self.app.find_config(path, "request.dispatch", self.dispatch)
-        
-        # dispatch() should set self.handler and self.config
-        dispatch(path)
-    
-    def handle_error(self):
-        """Handle the last unanticipated exception. (Core)"""
-        try:
-            self.hooks.run("before_error_response")
-            if self.error_response:
-                self.error_response()
-            self.hooks.run("after_error_response")
-            cherrypy.serving.response.finalize()
-        except cherrypy.HTTPRedirect, inst:
-            inst.set_response()
-            cherrypy.serving.response.finalize()
-    
-    # ------------------------- Properties ------------------------- #
-    
-    def _get_body_params(self):
-        warnings.warn(
-                "body_params is deprecated in CherryPy 3.2, will be removed in "
-                "CherryPy 3.3.",
-                DeprecationWarning
-            )
-        return self.body.params
-    body_params = property(_get_body_params,
-                      doc= """
-    If the request Content-Type is 'application/x-www-form-urlencoded' or
-    multipart, this will be a dict of the params pulled from the entity
-    body; that is, it will be the portion of request.params that come
-    from the message body (sometimes called "POST params", although they
-    can be sent with various HTTP method verbs). This value is set between
-    the 'before_request_body' and 'before_handler' hooks (assuming that
-    process_request_body is True).
-    
-    Deprecated in 3.2, will be removed for 3.3""")
-
-
-class ResponseBody(object):
-    """The body of the HTTP response (the response entity)."""
-    
-    def __get__(self, obj, objclass=None):
-        if obj is None:
-            # When calling on the class instead of an instance...
-            return self
-        else:
-            return obj._body
-    
-    def __set__(self, obj, value):
-        # Convert the given value to an iterable object.
-        if isinstance(value, basestring):
-            # strings get wrapped in a list because iterating over a single
-            # item list is much faster than iterating over every character
-            # in a long string.
-            if value:
-                value = [value]
-            else:
-                # [''] doesn't evaluate to False, so replace it with [].
-                value = []
-        elif isinstance(value, types.FileType):
-            value = file_generator(value)
-        elif value is None:
-            value = []
-        obj._body = value
-
-
-class Response(object):
-    """An HTTP Response, including status, headers, and body.
-    
-    Application developers should use Response.headers (a dict) to
-    set or modify HTTP response headers. When the response is finalized,
-    Response.headers is transformed into Response.header_list as
-    (key, value) tuples.
-    """
-    
-    __metaclass__ = cherrypy._AttributeDocstrings
-    
-    # Class attributes for dev-time introspection.
-    status = ""
-    status__doc = """The HTTP Status-Code and Reason-Phrase."""
-    
-    header_list = []
-    header_list__doc = """
-    A list of the HTTP response headers as (name, value) tuples.
-    In general, you should use response.headers (a dict) instead."""
-    
-    headers = httputil.HeaderMap()
-    headers__doc = """
-    A dict-like object containing the response headers. Keys are header
-    names (in Title-Case format); however, you may get and set them in
-    a case-insensitive manner. That is, headers['Content-Type'] and
-    headers['content-type'] refer to the same value. Values are header
-    values (decoded according to RFC 2047 if necessary). See also:
-    httputil.HeaderMap, httputil.HeaderElement."""
-    
-    cookie = SimpleCookie()
-    cookie__doc = """See help(Cookie)."""
-    
-    body = ResponseBody()
-    body__doc = """The body (entity) of the HTTP response."""
-    
-    time = None
-    time__doc = """The value of time.time() when created. Use in HTTP dates."""
-    
-    timeout = 300
-    timeout__doc = """Seconds after which the response will be aborted."""
-    
-    timed_out = False
-    timed_out__doc = """
-    Flag to indicate the response should be aborted, because it has
-    exceeded its timeout."""
-    
-    stream = False
-    stream__doc = """If False, buffer the response body."""
-    
-    def __init__(self):
-        self.status = None
-        self.header_list = None
-        self._body = []
-        self.time = time.time()
-        
-        self.headers = httputil.HeaderMap()
-        # Since we know all our keys are titled strings, we can
-        # bypass HeaderMap.update and get a big speed boost.
-        dict.update(self.headers, {
-            "Content-Type": 'text/html',
-            "Server": "CherryPy/" + cherrypy.__version__,
-            "Date": httputil.HTTPDate(self.time),
-        })
-        self.cookie = SimpleCookie()
-    
-    def collapse_body(self):
-        """Collapse self.body to a single string; replace it and return it."""
-        if isinstance(self.body, basestring):
-            return self.body
-
-        newbody = ''.join([chunk for chunk in self.body])
-        self.body = newbody
-        return newbody
-    
-    def finalize(self):
-        """Transform headers (and cookies) into self.header_list. (Core)"""
-        try:
-            code, reason, _ = httputil.valid_status(self.status)
-        except ValueError, x:
-            raise cherrypy.HTTPError(500, x.args[0])
-        
-        headers = self.headers
-        
-        self.output_status = str(code) + " " + headers.encode(reason)
-        
-        if self.stream:
-            # The upshot: wsgiserver will chunk the response if
-            # you pop Content-Length (or set it explicitly to None).
-            # Note that lib.static sets C-L to the file's st_size.
-            if dict.get(headers, 'Content-Length') is None:
-                dict.pop(headers, 'Content-Length', None)
-        elif code < 200 or code in (204, 205, 304):
-            # "All 1xx (informational), 204 (no content),
-            # and 304 (not modified) responses MUST NOT
-            # include a message-body."
-            dict.pop(headers, 'Content-Length', None)
-            self.body = ""
-        else:
-            # Responses which are not streamed should have a Content-Length,
-            # but allow user code to set Content-Length if desired.
-            if dict.get(headers, 'Content-Length') is None:
-                content = self.collapse_body()
-                dict.__setitem__(headers, 'Content-Length', len(content))
-        
-        # Transform our header dict into a list of tuples.
-        self.header_list = h = headers.output()
-        
-        cookie = self.cookie.output()
-        if cookie:
-            for line in cookie.split("\n"):
-                if line.endswith("\r"):
-                    # Python 2.4 emits cookies joined by LF but 2.5+ by CRLF.
-                    line = line[:-1]
-                name, value = line.split(": ", 1)
-                if isinstance(name, unicode):
-                    name = name.encode("ISO-8859-1")
-                if isinstance(value, unicode):
-                    value = headers.encode(value)
-                h.append((name, value))
-    
-    def check_timeout(self):
-        """If now > self.time + self.timeout, set self.timed_out.
-        
-        This purposefully sets a flag, rather than raising an error,
-        so that a monitor thread can interrupt the Response thread.
-        """
-        if time.time() > self.time + self.timeout:
-            self.timed_out = True
-
-
-
--- a/bundled/cherrypy/cherrypy/_cpserver.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,139 +0,0 @@
-"""Manage HTTP servers with CherryPy."""
-
-import warnings
-
-import cherrypy
-from cherrypy.lib import attributes
-
-# We import * because we want to export check_port
-# et al as attributes of this module.
-from cherrypy.process.servers import *
-
-
-class Server(ServerAdapter):
-    """An adapter for an HTTP server.
-    
-    You can set attributes (like socket_host and socket_port)
-    on *this* object (which is probably cherrypy.server), and call
-    quickstart. For example:
-    
-        cherrypy.server.socket_port = 80
-        cherrypy.quickstart()
-    """
-    
-    socket_port = 8080
-    
-    _socket_host = '127.0.0.1'
-    def _get_socket_host(self):
-        return self._socket_host
-    def _set_socket_host(self, value):
-        if value == '':
-            raise ValueError("The empty string ('') is not an allowed value. "
-                             "Use '0.0.0.0' instead to listen on all active "
-                             "interfaces (INADDR_ANY).")
-        self._socket_host = value
-    socket_host = property(_get_socket_host, _set_socket_host,
-        doc="""The hostname or IP address on which to listen for connections.
-        
-        Host values may be any IPv4 or IPv6 address, or any valid hostname.
-        The string 'localhost' is a synonym for '127.0.0.1' (or '::1', if
-        your hosts file prefers IPv6). The string '0.0.0.0' is a special
-        IPv4 entry meaning "any active interface" (INADDR_ANY), and '::'
-        is the similar IN6ADDR_ANY for IPv6. The empty string or None are
-        not allowed.""")
-    
-    socket_file = None
-    socket_queue_size = 5
-    socket_timeout = 10
-    shutdown_timeout = 5
-    protocol_version = 'HTTP/1.1'
-    reverse_dns = False
-    thread_pool = 10
-    thread_pool_max = -1
-    max_request_header_size = 500 * 1024
-    max_request_body_size = 100 * 1024 * 1024
-    instance = None
-    ssl_context = None
-    ssl_certificate = None
-    ssl_certificate_chain = None
-    ssl_private_key = None
-    ssl_module = 'pyopenssl'
-    nodelay = True
-    wsgi_version = (1, 1)
-    
-    def __init__(self):
-        self.bus = cherrypy.engine
-        self.httpserver = None
-        self.interrupt = None
-        self.running = False
-    
-    def httpserver_from_self(self, httpserver=None):
-        """Return a (httpserver, bind_addr) pair based on self attributes."""
-        if httpserver is None:
-            httpserver = self.instance
-        if httpserver is None:
-            from cherrypy import _cpwsgi_server
-            httpserver = _cpwsgi_server.CPWSGIServer(self)
-        if isinstance(httpserver, basestring):
-            # Is anyone using this? Can I add an arg?
-            httpserver = attributes(httpserver)(self)
-        return httpserver, self.bind_addr
-    
-    def start(self):
-        """Start the HTTP server."""
-        if not self.httpserver:
-            self.httpserver, self.bind_addr = self.httpserver_from_self()
-        ServerAdapter.start(self)
-    start.priority = 75
-    
-    def _get_bind_addr(self):
-        if self.socket_file:
-            return self.socket_file
-        if self.socket_host is None and self.socket_port is None:
-            return None
-        return (self.socket_host, self.socket_port)
-    def _set_bind_addr(self, value):
-        if value is None:
-            self.socket_file = None
-            self.socket_host = None
-            self.socket_port = None
-        elif isinstance(value, basestring):
-            self.socket_file = value
-            self.socket_host = None
-            self.socket_port = None
-        else:
-            try:
-                self.socket_host, self.socket_port = value
-                self.socket_file = None
-            except ValueError:
-                raise ValueError("bind_addr must be a (host, port) tuple "
-                                 "(for TCP sockets) or a string (for Unix "
-                                 "domain sockets), not %r" % value)
-    bind_addr = property(_get_bind_addr, _set_bind_addr)
-    
-    def base(self):
-        """Return the base (scheme://host[:port] or sock file) for this server."""
-        if self.socket_file:
-            return self.socket_file
-        
-        host = self.socket_host
-        if host in ('0.0.0.0', '::'):
-            # 0.0.0.0 is INADDR_ANY and :: is IN6ADDR_ANY.
-            # Look up the host name, which should be the
-            # safest thing to spit out in a URL.
-            import socket
-            host = socket.gethostname()
-        
-        port = self.socket_port
-        
-        if self.ssl_certificate:
-            scheme = "https"
-            if port != 443:
-                host += ":%s" % port
-        else:
-            scheme = "http"
-            if port != 80:
-                host += ":%s" % port
-        
-        return "%s://%s" % (scheme, host)
-
--- a/bundled/cherrypy/cherrypy/_cpthreadinglocal.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,239 +0,0 @@
-# This is a backport of Python-2.4's threading.local() implementation
-
-"""Thread-local objects
-
-(Note that this module provides a Python version of thread
- threading.local class.  Depending on the version of Python you're
- using, there may be a faster one available.  You should always import
- the local class from threading.)
-
-Thread-local objects support the management of thread-local data.
-If you have data that you want to be local to a thread, simply create
-a thread-local object and use its attributes:
-
-  >>> mydata = local()
-  >>> mydata.number = 42
-  >>> mydata.number
-  42
-
-You can also access the local-object's dictionary:
-
-  >>> mydata.__dict__
-  {'number': 42}
-  >>> mydata.__dict__.setdefault('widgets', [])
-  []
-  >>> mydata.widgets
-  []
-
-What's important about thread-local objects is that their data are
-local to a thread. If we access the data in a different thread:
-
-  >>> log = []
-  >>> def f():
-  ...     items = mydata.__dict__.items()
-  ...     items.sort()
-  ...     log.append(items)
-  ...     mydata.number = 11
-  ...     log.append(mydata.number)
-
-  >>> import threading
-  >>> thread = threading.Thread(target=f)
-  >>> thread.start()
-  >>> thread.join()
-  >>> log
-  [[], 11]
-
-we get different data.  Furthermore, changes made in the other thread
-don't affect data seen in this thread:
-
-  >>> mydata.number
-  42
-
-Of course, values you get from a local object, including a __dict__
-attribute, are for whatever thread was current at the time the
-attribute was read.  For that reason, you generally don't want to save
-these values across threads, as they apply only to the thread they
-came from.
-
-You can create custom local objects by subclassing the local class:
-
-  >>> class MyLocal(local):
-  ...     number = 2
-  ...     initialized = False
-  ...     def __init__(self, **kw):
-  ...         if self.initialized:
-  ...             raise SystemError('__init__ called too many times')
-  ...         self.initialized = True
-  ...         self.__dict__.update(kw)
-  ...     def squared(self):
-  ...         return self.number ** 2
-
-This can be useful to support default values, methods and
-initialization.  Note that if you define an __init__ method, it will be
-called each time the local object is used in a separate thread.  This
-is necessary to initialize each thread's dictionary.
-
-Now if we create a local object:
-
-  >>> mydata = MyLocal(color='red')
-
-Now we have a default number:
-
-  >>> mydata.number
-  2
-
-an initial color:
-
-  >>> mydata.color
-  'red'
-  >>> del mydata.color
-
-And a method that operates on the data:
-
-  >>> mydata.squared()
-  4
-
-As before, we can access the data in a separate thread:
-
-  >>> log = []
-  >>> thread = threading.Thread(target=f)
-  >>> thread.start()
-  >>> thread.join()
-  >>> log
-  [[('color', 'red'), ('initialized', True)], 11]
-
-without affecting this thread's data:
-
-  >>> mydata.number
-  2
-  >>> mydata.color
-  Traceback (most recent call last):
-  ...
-  AttributeError: 'MyLocal' object has no attribute 'color'
-
-Note that subclasses can define slots, but they are not thread
-local. They are shared across threads:
-
-  >>> class MyLocal(local):
-  ...     __slots__ = 'number'
-
-  >>> mydata = MyLocal()
-  >>> mydata.number = 42
-  >>> mydata.color = 'red'
-
-So, the separate thread:
-
-  >>> thread = threading.Thread(target=f)
-  >>> thread.start()
-  >>> thread.join()
-
-affects what we see:
-
-  >>> mydata.number
-  11
-
->>> del mydata
-"""
-
-# Threading import is at end
-
-class _localbase(object):
-    __slots__ = '_local__key', '_local__args', '_local__lock'
-
-    def __new__(cls, *args, **kw):
-        self = object.__new__(cls)
-        key = 'thread.local.' + str(id(self))
-        object.__setattr__(self, '_local__key', key)
-        object.__setattr__(self, '_local__args', (args, kw))
-        object.__setattr__(self, '_local__lock', RLock())
-
-        if args or kw and (cls.__init__ is object.__init__):
-            raise TypeError("Initialization arguments are not supported")
-
-        # We need to create the thread dict in anticipation of
-        # __init__ being called, to make sure we don't call it
-        # again ourselves.
-        dict = object.__getattribute__(self, '__dict__')
-        currentThread().__dict__[key] = dict
-
-        return self
-
-def _patch(self):
-    key = object.__getattribute__(self, '_local__key')
-    d = currentThread().__dict__.get(key)
-    if d is None:
-        d = {}
-        currentThread().__dict__[key] = d
-        object.__setattr__(self, '__dict__', d)
-
-        # we have a new instance dict, so call out __init__ if we have
-        # one
-        cls = type(self)
-        if cls.__init__ is not object.__init__:
-            args, kw = object.__getattribute__(self, '_local__args')
-            cls.__init__(self, *args, **kw)
-    else:
-        object.__setattr__(self, '__dict__', d)
-
-class local(_localbase):
-
-    def __getattribute__(self, name):
-        lock = object.__getattribute__(self, '_local__lock')
-        lock.acquire()
-        try:
-            _patch(self)
-            return object.__getattribute__(self, name)
-        finally:
-            lock.release()
-
-    def __setattr__(self, name, value):
-        lock = object.__getattribute__(self, '_local__lock')
-        lock.acquire()
-        try:
-            _patch(self)
-            return object.__setattr__(self, name, value)
-        finally:
-            lock.release()
-
-    def __delattr__(self, name):
-        lock = object.__getattribute__(self, '_local__lock')
-        lock.acquire()
-        try:
-            _patch(self)
-            return object.__delattr__(self, name)
-        finally:
-            lock.release()
-
-
-    def __del__():
-        threading_enumerate = enumerate
-        __getattribute__ = object.__getattribute__
-
-        def __del__(self):
-            key = __getattribute__(self, '_local__key')
-
-            try:
-                threads = list(threading_enumerate())
-            except:
-                # if enumerate fails, as it seems to do during
-                # shutdown, we'll skip cleanup under the assumption
-                # that there is nothing to clean up
-                return
-
-            for thread in threads:
-                try:
-                    __dict__ = thread.__dict__
-                except AttributeError:
-                    # Thread is dying, rest in peace
-                    continue
-
-                if key in __dict__:
-                    try:
-                        del __dict__[key]
-                    except KeyError:
-                        pass # didn't have anything in this thread
-
-        return __del__
-    __del__ = __del__()
-
-from threading import currentThread, enumerate, RLock
--- a/bundled/cherrypy/cherrypy/_cptools.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,498 +0,0 @@
-"""CherryPy tools. A "tool" is any helper, adapted to CP.
-
-Tools are usually designed to be used in a variety of ways (although some
-may only offer one if they choose):
-    
-    Library calls:
-        All tools are callables that can be used wherever needed.
-        The arguments are straightforward and should be detailed within the
-        docstring.
-    
-    Function decorators:
-        All tools, when called, may be used as decorators which configure
-        individual CherryPy page handlers (methods on the CherryPy tree).
-        That is, "@tools.anytool()" should "turn on" the tool via the
-        decorated function's _cp_config attribute.
-    
-    CherryPy config:
-        If a tool exposes a "_setup" callable, it will be called
-        once per Request (if the feature is "turned on" via config).
-
-Tools may be implemented as any object with a namespace. The builtins
-are generally either modules or instances of the tools.Tool class.
-"""
-
-import cherrypy
-import warnings
-
-
-def _getargs(func):
-    """Return the names of all static arguments to the given function."""
-    # Use this instead of importing inspect for less mem overhead.
-    import types
-    if isinstance(func, types.MethodType):
-        func = func.im_func
-    co = func.func_code
-    return co.co_varnames[:co.co_argcount]
-
-
-_attr_error = ("CherryPy Tools cannot be turned on directly. Instead, turn them "
-               "on via config, or use them as decorators on your page handlers.")
-
-class Tool(object):
-    """A registered function for use with CherryPy request-processing hooks.
-    
-    help(tool.callable) should give you more information about this Tool.
-    """
-    
-    namespace = "tools"
-    
-    def __init__(self, point, callable, name=None, priority=50):
-        self._point = point
-        self.callable = callable
-        self._name = name
-        self._priority = priority
-        self.__doc__ = self.callable.__doc__
-        self._setargs()
-    
-    def _get_on(self):
-        raise AttributeError(_attr_error)
-    def _set_on(self, value):
-        raise AttributeError(_attr_error)
-    on = property(_get_on, _set_on)
-    
-    def _setargs(self):
-        """Copy func parameter names to obj attributes."""
-        try:
-            for arg in _getargs(self.callable):
-                setattr(self, arg, None)
-        except (TypeError, AttributeError):
-            if hasattr(self.callable, "__call__"):
-                for arg in _getargs(self.callable.__call__):
-                    setattr(self, arg, None)
-        # IronPython 1.0 raises NotImplementedError because
-        # inspect.getargspec tries to access Python bytecode
-        # in co_code attribute.
-        except NotImplementedError:
-            pass
-        # IronPython 1B1 may raise IndexError in some cases,
-        # but if we trap it here it doesn't prevent CP from working.
-        except IndexError:
-            pass
-    
-    def _merged_args(self, d=None):
-        """Return a dict of configuration entries for this Tool."""
-        if d:
-            conf = d.copy()
-        else:
-            conf = {}
-        
-        tm = cherrypy.serving.request.toolmaps[self.namespace]
-        if self._name in tm:
-            conf.update(tm[self._name])
-        
-        if "on" in conf:
-            del conf["on"]
-        
-        return conf
-    
-    def __call__(self, *args, **kwargs):
-        """Compile-time decorator (turn on the tool in config).
-        
-        For example:
-        
-            @tools.proxy()
-            def whats_my_base(self):
-                return cherrypy.request.base
-            whats_my_base.exposed = True
-        """
-        if args:
-            raise TypeError("The %r Tool does not accept positional "
-                            "arguments; you must use keyword arguments."
-                            % self._name)
-        def tool_decorator(f):
-            if not hasattr(f, "_cp_config"):
-                f._cp_config = {}
-            subspace = self.namespace + "." + self._name + "."
-            f._cp_config[subspace + "on"] = True
-            for k, v in kwargs.items():
-                f._cp_config[subspace + k] = v
-            return f
-        return tool_decorator
-    
-    def _setup(self):
-        """Hook this tool into cherrypy.request.
-        
-        The standard CherryPy request object will automatically call this
-        method when the tool is "turned on" in config.
-        """
-        conf = self._merged_args()
-        p = conf.pop("priority", None)
-        if p is None:
-            p = getattr(self.callable, "priority", self._priority)
-        cherrypy.serving.request.hooks.attach(self._point, self.callable,
-                                              priority=p, **conf)
-
-
-class HandlerTool(Tool):
-    """Tool which is called 'before main', that may skip normal handlers.
-    
-    If the tool successfully handles the request (by setting response.body),
-    if should return True. This will cause CherryPy to skip any 'normal' page
-    handler. If the tool did not handle the request, it should return False
-    to tell CherryPy to continue on and call the normal page handler. If the
-    tool is declared AS a page handler (see the 'handler' method), returning
-    False will raise NotFound.
-    """
-    
-    def __init__(self, callable, name=None):
-        Tool.__init__(self, 'before_handler', callable, name)
-    
-    def handler(self, *args, **kwargs):
-        """Use this tool as a CherryPy page handler.
-        
-        For example:
-            class Root:
-                nav = tools.staticdir.handler(section="/nav", dir="nav",
-                                              root=absDir)
-        """
-        def handle_func(*a, **kw):
-            handled = self.callable(*args, **self._merged_args(kwargs))
-            if not handled:
-                raise cherrypy.NotFound()
-            return cherrypy.serving.response.body
-        handle_func.exposed = True
-        return handle_func
-    
-    def _wrapper(self, **kwargs):
-        if self.callable(**kwargs):
-            cherrypy.serving.request.handler = None
-    
-    def _setup(self):
-        """Hook this tool into cherrypy.request.
-        
-        The standard CherryPy request object will automatically call this
-        method when the tool is "turned on" in config.
-        """
-        conf = self._merged_args()
-        p = conf.pop("priority", None)
-        if p is None:
-            p = getattr(self.callable, "priority", self._priority)
-        cherrypy.serving.request.hooks.attach(self._point, self._wrapper,
-                                              priority=p, **conf)
-
-
-class HandlerWrapperTool(Tool):
-    """Tool which wraps request.handler in a provided wrapper function.
-    
-    The 'newhandler' arg must be a handler wrapper function that takes a
-    'next_handler' argument, plus *args and **kwargs. Like all page handler
-    functions, it must return an iterable for use as cherrypy.response.body.
-    
-    For example, to allow your 'inner' page handlers to return dicts
-    which then get interpolated into a template:
-    
-        def interpolator(next_handler, *args, **kwargs):
-            filename = cherrypy.request.config.get('template')
-            cherrypy.response.template = env.get_template(filename)
-            response_dict = next_handler(*args, **kwargs)
-            return cherrypy.response.template.render(**response_dict)
-        cherrypy.tools.jinja = HandlerWrapperTool(interpolator)
-    """
-    
-    def __init__(self, newhandler, point='before_handler', name=None, priority=50):
-        self.newhandler = newhandler
-        self._point = point
-        self._name = name
-        self._priority = priority
-    
-    def callable(self, debug=False):
-        innerfunc = cherrypy.serving.request.handler
-        def wrap(*args, **kwargs):
-            return self.newhandler(innerfunc, *args, **kwargs)
-        cherrypy.serving.request.handler = wrap
-
-
-class ErrorTool(Tool):
-    """Tool which is used to replace the default request.error_response."""
-    
-    def __init__(self, callable, name=None):
-        Tool.__init__(self, None, callable, name)
-    
-    def _wrapper(self):
-        self.callable(**self._merged_args())
-    
-    def _setup(self):
-        """Hook this tool into cherrypy.request.
-        
-        The standard CherryPy request object will automatically call this
-        method when the tool is "turned on" in config.
-        """
-        cherrypy.serving.request.error_response = self._wrapper
-
-
-#                              Builtin tools                              #
-
-from cherrypy.lib import cptools, encoding, auth, static, jsontools
-from cherrypy.lib import sessions as _sessions, xmlrpc as _xmlrpc
-from cherrypy.lib import caching as _caching
-from cherrypy.lib import auth_basic, auth_digest
-
-
-class SessionTool(Tool):
-    """Session Tool for CherryPy.
-    
-    sessions.locking:
-        When 'implicit' (the default), the session will be locked for you,
-            just before running the page handler.
-        When 'early', the session will be locked before reading the request
-            body. This is off by default for safety reasons; for example,
-            a large upload would block the session, denying an AJAX
-            progress meter (see http://www.cherrypy.org/ticket/630).
-        When 'explicit' (or any other value), you need to call
-            cherrypy.session.acquire_lock() yourself before using
-            session data.
-    """
-    
-    def __init__(self):
-        # _sessions.init must be bound after headers are read
-        Tool.__init__(self, 'before_request_body', _sessions.init)
-    
-    def _lock_session(self):
-        cherrypy.serving.session.acquire_lock()
-    
-    def _setup(self):
-        """Hook this tool into cherrypy.request.
-        
-        The standard CherryPy request object will automatically call this
-        method when the tool is "turned on" in config.
-        """
-        hooks = cherrypy.serving.request.hooks
-        
-        conf = self._merged_args()
-        
-        p = conf.pop("priority", None)
-        if p is None:
-            p = getattr(self.callable, "priority", self._priority)
-        
-        hooks.attach(self._point, self.callable, priority=p, **conf)
-        
-        locking = conf.pop('locking', 'implicit')
-        if locking == 'implicit':
-            hooks.attach('before_handler', self._lock_session)
-        elif locking == 'early':
-            # Lock before the request body (but after _sessions.init runs!)
-            hooks.attach('before_request_body', self._lock_session,
-                         priority=60)
-        else:
-            # Don't lock
-            pass
-        
-        hooks.attach('before_finalize', _sessions.save)
-        hooks.attach('on_end_request', _sessions.close)
-        
-    def regenerate(self):
-        """Drop the current session and make a new one (with a new id)."""
-        sess = cherrypy.serving.session
-        sess.regenerate()
-        
-        # Grab cookie-relevant tool args
-        conf = dict([(k, v) for k, v in self._merged_args().items()
-                     if k in ('path', 'path_header', 'name', 'timeout',
-                              'domain', 'secure')])
-        _sessions.set_response_cookie(**conf)
-
-
-
-
-class XMLRPCController(object):
-    """A Controller (page handler collection) for XML-RPC.
-    
-    To use it, have your controllers subclass this base class (it will
-    turn on the tool for you).
-    
-    You can also supply the following optional config entries:
-        
-        tools.xmlrpc.encoding: 'utf-8'
-        tools.xmlrpc.allow_none: 0
-    
-    XML-RPC is a rather discontinuous layer over HTTP; dispatching to the
-    appropriate handler must first be performed according to the URL, and
-    then a second dispatch step must take place according to the RPC method
-    specified in the request body. It also allows a superfluous "/RPC2"
-    prefix in the URL, supplies its own handler args in the body, and
-    requires a 200 OK "Fault" response instead of 404 when the desired
-    method is not found.
-    
-    Therefore, XML-RPC cannot be implemented for CherryPy via a Tool alone.
-    This Controller acts as the dispatch target for the first half (based
-    on the URL); it then reads the RPC method from the request body and
-    does its own second dispatch step based on that method. It also reads
-    body params, and returns a Fault on error.
-    
-    The XMLRPCDispatcher strips any /RPC2 prefix; if you aren't using /RPC2
-    in your URL's, you can safely skip turning on the XMLRPCDispatcher.
-    Otherwise, you need to use declare it in config:
-        
-        request.dispatch: cherrypy.dispatch.XMLRPCDispatcher()
-    """
-    
-    # Note we're hard-coding this into the 'tools' namespace. We could do
-    # a huge amount of work to make it relocatable, but the only reason why
-    # would be if someone actually disabled the default_toolbox. Meh.
-    _cp_config = {'tools.xmlrpc.on': True}
-    
-    def default(self, *vpath, **params):
-        rpcparams, rpcmethod = _xmlrpc.process_body()
-        
-        subhandler = self
-        for attr in str(rpcmethod).split('.'):
-            subhandler = getattr(subhandler, attr, None)
-         
-        if subhandler and getattr(subhandler, "exposed", False):
-            body = subhandler(*(vpath + rpcparams), **params)
-        
-        else:
-            # http://www.cherrypy.org/ticket/533
-            # if a method is not found, an xmlrpclib.Fault should be returned
-            # raising an exception here will do that; see
-            # cherrypy.lib.xmlrpc.on_error
-            raise Exception('method "%s" is not supported' % attr)
-        
-        conf = cherrypy.serving.request.toolmaps['tools'].get("xmlrpc", {})
-        _xmlrpc.respond(body,
-                        conf.get('encoding', 'utf-8'),
-                        conf.get('allow_none', 0))
-        return cherrypy.serving.response.body
-    default.exposed = True
-
-
-class SessionAuthTool(HandlerTool):
-    
-    def _setargs(self):
-        for name in dir(cptools.SessionAuth):
-            if not name.startswith("__"):
-                setattr(self, name, None)
-
-
-class CachingTool(Tool):
-    """Caching Tool for CherryPy."""
-    
-    def _wrapper(self, **kwargs):
-        request = cherrypy.serving.request
-        if _caching.get(**kwargs):
-            request.handler = None
-        else:
-            if request.cacheable:
-                # Note the devious technique here of adding hooks on the fly
-                request.hooks.attach('before_finalize', _caching.tee_output,
-                                     priority = 90)
-    _wrapper.priority = 20
-    
-    def _setup(self):
-        """Hook caching into cherrypy.request."""
-        conf = self._merged_args()
-        
-        p = conf.pop("priority", None)
-        cherrypy.serving.request.hooks.attach('before_handler', self._wrapper,
-                                              priority=p, **conf)
-
-
-
-class Toolbox(object):
-    """A collection of Tools.
-    
-    This object also functions as a config namespace handler for itself.
-    Custom toolboxes should be added to each Application's toolboxes dict.
-    """
-    
-    def __init__(self, namespace):
-        self.namespace = namespace
-    
-    def __setattr__(self, name, value):
-        # If the Tool._name is None, supply it from the attribute name.
-        if isinstance(value, Tool):
-            if value._name is None:
-                value._name = name
-            value.namespace = self.namespace
-        object.__setattr__(self, name, value)
-    
-    def __enter__(self):
-        """Populate request.toolmaps from tools specified in config."""
-        cherrypy.serving.request.toolmaps[self.namespace] = map = {}
-        def populate(k, v):
-            toolname, arg = k.split(".", 1)
-            bucket = map.setdefault(toolname, {})
-            bucket[arg] = v
-        return populate
-    
-    def __exit__(self, exc_type, exc_val, exc_tb):
-        """Run tool._setup() for each tool in our toolmap."""
-        map = cherrypy.serving.request.toolmaps.get(self.namespace)
-        if map:
-            for name, settings in map.items():
-                if settings.get("on", False):
-                    tool = getattr(self, name)
-                    tool._setup()
-
-
-class DeprecatedTool(Tool):
-    
-    _name = None
-    warnmsg = "This Tool is deprecated."
-    
-    def __init__(self, point, warnmsg=None):
-        self.point = point
-        if warnmsg is not None:
-            self.warnmsg = warnmsg
-    
-    def __call__(self, *args, **kwargs):
-        warnings.warn(self.warnmsg)
-        def tool_decorator(f):
-            return f
-        return tool_decorator
-    
-    def _setup(self):
-        warnings.warn(self.warnmsg)
-
-
-default_toolbox = _d = Toolbox("tools")
-_d.session_auth = SessionAuthTool(cptools.session_auth)
-_d.proxy = Tool('before_request_body', cptools.proxy, priority=30)
-_d.response_headers = Tool('on_start_resource', cptools.response_headers)
-_d.log_tracebacks = Tool('before_error_response', cptools.log_traceback)
-_d.log_headers = Tool('before_error_response', cptools.log_request_headers)
-_d.log_hooks = Tool('on_end_request', cptools.log_hooks, priority=100)
-_d.err_redirect = ErrorTool(cptools.redirect)
-_d.etags = Tool('before_finalize', cptools.validate_etags, priority=75)
-_d.decode = Tool('before_request_body', encoding.decode)
-# the order of encoding, gzip, caching is important
-_d.encode = Tool('before_handler', encoding.ResponseEncoder, priority=70)
-_d.gzip = Tool('before_finalize', encoding.gzip, priority=80)
-_d.staticdir = HandlerTool(static.staticdir)
-_d.staticfile = HandlerTool(static.staticfile)
-_d.sessions = SessionTool()
-_d.xmlrpc = ErrorTool(_xmlrpc.on_error)
-_d.caching = CachingTool('before_handler', _caching.get, 'caching')
-_d.expires = Tool('before_finalize', _caching.expires)
-_d.tidy = DeprecatedTool('before_finalize',
-    "The tidy tool has been removed from the standard distribution of CherryPy. "
-    "The most recent version can be found at http://tools.cherrypy.org/browser.")
-_d.nsgmls = DeprecatedTool('before_finalize',
-    "The nsgmls tool has been removed from the standard distribution of CherryPy. "
-    "The most recent version can be found at http://tools.cherrypy.org/browser.")
-_d.ignore_headers = Tool('before_request_body', cptools.ignore_headers)
-_d.referer = Tool('before_request_body', cptools.referer)
-_d.basic_auth = Tool('on_start_resource', auth.basic_auth)
-_d.digest_auth = Tool('on_start_resource', auth.digest_auth)
-_d.trailing_slash = Tool('before_handler', cptools.trailing_slash, priority=60)
-_d.flatten = Tool('before_finalize', cptools.flatten)
-_d.accept = Tool('on_start_resource', cptools.accept)
-_d.redirect = Tool('on_start_resource', cptools.redirect)
-_d.autovary = Tool('on_start_resource', cptools.autovary, priority=0)
-_d.json_in = Tool('before_request_body', jsontools.json_in, priority=30)
-_d.json_out = Tool('before_handler', jsontools.json_out, priority=30)
-_d.auth_basic = Tool('before_handler', auth_basic.basic_auth, priority=1)
-_d.auth_digest = Tool('before_handler', auth_digest.digest_auth, priority=1)
-
-del _d, cptools, encoding, auth, static
--- a/bundled/cherrypy/cherrypy/_cptree.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,278 +0,0 @@
-"""CherryPy Application and Tree objects."""
-
-import os
-import cherrypy
-from cherrypy import _cpconfig, _cplogging, _cprequest, _cpwsgi, tools
-from cherrypy.lib import httputil
-
-
-class Application(object):
-    """A CherryPy Application.
-    
-    Servers and gateways should not instantiate Request objects directly.
-    Instead, they should ask an Application object for a request object.
-    
-    An instance of this class may also be used as a WSGI callable
-    (WSGI application object) for itself.
-    """
-    
-    __metaclass__ = cherrypy._AttributeDocstrings
-    
-    root = None
-    root__doc = """
-    The top-most container of page handlers for this app. Handlers should
-    be arranged in a hierarchy of attributes, matching the expected URI
-    hierarchy; the default dispatcher then searches this hierarchy for a
-    matching handler. When using a dispatcher other than the default,
-    this value may be None."""
-    
-    config = {}
-    config__doc = """
-    A dict of {path: pathconf} pairs, where 'pathconf' is itself a dict
-    of {key: value} pairs."""
-    
-    namespaces = _cpconfig.NamespaceSet()
-    toolboxes = {'tools': cherrypy.tools}
-    
-    log = None
-    log__doc = """A LogManager instance. See _cplogging."""
-    
-    wsgiapp = None
-    wsgiapp__doc = """A CPWSGIApp instance. See _cpwsgi."""
-    
-    request_class = _cprequest.Request
-    response_class = _cprequest.Response
-    
-    relative_urls = False
-    
-    def __init__(self, root, script_name="", config=None):
-        self.log = _cplogging.LogManager(id(self), cherrypy.log.logger_root)
-        self.root = root
-        self.script_name = script_name
-        self.wsgiapp = _cpwsgi.CPWSGIApp(self)
-        
-        self.namespaces = self.namespaces.copy()
-        self.namespaces["log"] = lambda k, v: setattr(self.log, k, v)
-        self.namespaces["wsgi"] = self.wsgiapp.namespace_handler
-        
-        self.config = self.__class__.config.copy()
-        if config:
-            self.merge(config)
-    
-    def __repr__(self):
-        return "%s.%s(%r, %r)" % (self.__module__, self.__class__.__name__,
-                                  self.root, self.script_name)
-    
-    script_name__doc = """
-    The URI "mount point" for this app. A mount point is that portion of
-    the URI which is constant for all URIs that are serviced by this
-    application; it does not include scheme, host, or proxy ("virtual host")
-    portions of the URI.
-    
-    For example, if script_name is "/my/cool/app", then the URL
-    "http://www.example.com/my/cool/app/page1" might be handled by a
-    "page1" method on the root object.
-    
-    The value of script_name MUST NOT end in a slash. If the script_name
-    refers to the root of the URI, it MUST be an empty string (not "/").
-    
-    If script_name is explicitly set to None, then the script_name will be
-    provided for each call from request.wsgi_environ['SCRIPT_NAME'].
-    """
-    def _get_script_name(self):
-        if self._script_name is None:
-            # None signals that the script name should be pulled from WSGI environ.
-            return cherrypy.serving.request.wsgi_environ['SCRIPT_NAME'].rstrip("/")
-        return self._script_name
-    def _set_script_name(self, value):
-        if value:
-            value = value.rstrip("/")
-        self._script_name = value
-    script_name = property(fget=_get_script_name, fset=_set_script_name,
-                           doc=script_name__doc)
-    
-    def merge(self, config):
-        """Merge the given config into self.config."""
-        _cpconfig.merge(self.config, config)
-        
-        # Handle namespaces specified in config.
-        self.namespaces(self.config.get("/", {}))
-    
-    def find_config(self, path, key, default=None):
-        """Return the most-specific value for key along path, or default."""
-        trail = path or "/"
-        while trail:
-            nodeconf = self.config.get(trail, {})
-            
-            if key in nodeconf:
-                return nodeconf[key]
-            
-            lastslash = trail.rfind("/")
-            if lastslash == -1:
-                break
-            elif lastslash == 0 and trail != "/":
-                trail = "/"
-            else:
-                trail = trail[:lastslash]
-        
-        return default
-    
-    def get_serving(self, local, remote, scheme, sproto):
-        """Create and return a Request and Response object."""
-        req = self.request_class(local, remote, scheme, sproto)
-        req.app = self
-        
-        for name, toolbox in self.toolboxes.items():
-            req.namespaces[name] = toolbox
-        
-        resp = self.response_class()
-        cherrypy.serving.load(req, resp)
-        cherrypy.engine.timeout_monitor.acquire()
-        cherrypy.engine.publish('acquire_thread')
-        
-        return req, resp
-    
-    def release_serving(self):
-        """Release the current serving (request and response)."""
-        req = cherrypy.serving.request
-        
-        cherrypy.engine.timeout_monitor.release()
-        
-        try:
-            req.close()
-        except:
-            cherrypy.log(traceback=True, severity=40)
-        
-        cherrypy.serving.clear()
-    
-    def __call__(self, environ, start_response):
-        return self.wsgiapp(environ, start_response)
-
-
-class Tree(object):
-    """A registry of CherryPy applications, mounted at diverse points.
-    
-    An instance of this class may also be used as a WSGI callable
-    (WSGI application object), in which case it dispatches to all
-    mounted apps.
-    """
-    
-    apps = {}
-    apps__doc = """
-    A dict of the form {script name: application}, where "script name"
-    is a string declaring the URI mount point (no trailing slash), and
-    "application" is an instance of cherrypy.Application (or an arbitrary
-    WSGI callable if you happen to be using a WSGI server)."""
-    
-    def __init__(self):
-        self.apps = {}
-    
-    def mount(self, root, script_name="", config=None):
-        """Mount a new app from a root object, script_name, and config.
-        
-        root: an instance of a "controller class" (a collection of page
-            handler methods) which represents the root of the application.
-            This may also be an Application instance, or None if using
-            a dispatcher other than the default.
-        script_name: a string containing the "mount point" of the application.
-            This should start with a slash, and be the path portion of the
-            URL at which to mount the given root. For example, if root.index()
-            will handle requests to "http://www.example.com:8080/dept/app1/",
-            then the script_name argument would be "/dept/app1".
-            
-            It MUST NOT end in a slash. If the script_name refers to the
-            root of the URI, it MUST be an empty string (not "/").
-        config: a file or dict containing application config.
-        """
-        if script_name is None:
-            raise TypeError(
-                "The 'script_name' argument may not be None. Application "
-                "objects may, however, possess a script_name of None (in "
-                "order to inpect the WSGI environ for SCRIPT_NAME upon each "
-                "request). You cannot mount such Applications on this Tree; "
-                "you must pass them to a WSGI server interface directly.")
-        
-        # Next line both 1) strips trailing slash and 2) maps "/" -> "".
-        script_name = script_name.rstrip("/")
-        
-        if isinstance(root, Application):
-            app = root
-            if script_name != "" and script_name != app.script_name:
-                raise ValueError("Cannot specify a different script name and "
-                                 "pass an Application instance to cherrypy.mount")
-            script_name = app.script_name
-        else:
-            app = Application(root, script_name)
-            
-            # If mounted at "", add favicon.ico
-            if (script_name == "" and root is not None
-                    and not hasattr(root, "favicon_ico")):
-                favicon = os.path.join(os.getcwd(), os.path.dirname(__file__),
-                                       "favicon.ico")
-                root.favicon_ico = tools.staticfile.handler(favicon)
-        
-        if config:
-            app.merge(config)
-        
-        self.apps[script_name] = app
-        
-        return app
-    
-    def graft(self, wsgi_callable, script_name=""):
-        """Mount a wsgi callable at the given script_name."""
-        # Next line both 1) strips trailing slash and 2) maps "/" -> "".
-        script_name = script_name.rstrip("/")
-        self.apps[script_name] = wsgi_callable
-    
-    def script_name(self, path=None):
-        """The script_name of the app at the given path, or None.
-        
-        If path is None, cherrypy.request is used.
-        """
-        if path is None:
-            try:
-                request = cherrypy.serving.request
-                path = httputil.urljoin(request.script_name,
-                                        request.path_info)
-            except AttributeError:
-                return None
-        
-        while True:
-            if path in self.apps:
-                return path
-            
-            if path == "":
-                return None
-            
-            # Move one node up the tree and try again.
-            path = path[:path.rfind("/")]
-    
-    def __call__(self, environ, start_response):
-        # If you're calling this, then you're probably setting SCRIPT_NAME
-        # to '' (some WSGI servers always set SCRIPT_NAME to '').
-        # Try to look up the app using the full path.
-        env1x = environ
-        if environ.get(u'wsgi.version') == (u'u', 0):
-            env1x = _cpwsgi.downgrade_wsgi_ux_to_1x(environ)
-        path = httputil.urljoin(env1x.get('SCRIPT_NAME', ''),
-                                env1x.get('PATH_INFO', ''))
-        sn = self.script_name(path or "/")
-        if sn is None:
-            start_response('404 Not Found', [])
-            return []
-        
-        app = self.apps[sn]
-        
-        # Correct the SCRIPT_NAME and PATH_INFO environ entries.
-        environ = environ.copy()
-        if environ.get(u'wsgi.version') == (u'u', 0):
-            # Python 2/WSGI u.0: all strings MUST be of type unicode
-            enc = environ[u'wsgi.url_encoding']
-            environ[u'SCRIPT_NAME'] = sn.decode(enc)
-            environ[u'PATH_INFO'] = path[len(sn.rstrip("/")):].decode(enc)
-        else:
-            # Python 2/WSGI 1.x: all strings MUST be of type str
-            environ['SCRIPT_NAME'] = sn
-            environ['PATH_INFO'] = path[len(sn.rstrip("/")):]
-        return app(environ, start_response)
-
--- a/bundled/cherrypy/cherrypy/_cpwsgi.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,340 +0,0 @@
-"""WSGI interface (see PEP 333)."""
-
-import sys as _sys
-
-import cherrypy as _cherrypy
-try:
-    from cStringIO import StringIO
-except ImportError:
-    from StringIO import StringIO
-from cherrypy import _cperror
-from cherrypy.lib import httputil
-
-
-def downgrade_wsgi_ux_to_1x(environ):
-    """Return a new environ dict for WSGI 1.x from the given WSGI u.x environ."""
-    env1x = {}
-    
-    url_encoding = environ[u'wsgi.url_encoding']
-    for k, v in environ.items():
-        if k in [u'PATH_INFO', u'SCRIPT_NAME', u'QUERY_STRING']:
-            v = v.encode(url_encoding)
-        elif isinstance(v, unicode):
-            v = v.encode('ISO-8859-1')
-        env1x[k.encode('ISO-8859-1')] = v
-    
-    return env1x
-
-
-class VirtualHost(object):
-    """Select a different WSGI application based on the Host header.
-    
-    This can be useful when running multiple sites within one CP server.
-    It allows several domains to point to different applications. For example:
-    
-        root = Root()
-        RootApp = cherrypy.Application(root)
-        Domain2App = cherrypy.Application(root)
-        SecureApp = cherrypy.Application(Secure())
-        
-        vhost = cherrypy._cpwsgi.VirtualHost(RootApp,
-            domains={'www.domain2.example': Domain2App,
-                     'www.domain2.example:443': SecureApp,
-                     })
-        
-        cherrypy.tree.graft(vhost)
-    
-    default: required. The default WSGI application.
-    
-    use_x_forwarded_host: if True (the default), any "X-Forwarded-Host"
-        request header will be used instead of the "Host" header. This
-        is commonly added by HTTP servers (such as Apache) when proxying.
-    
-    domains: a dict of {host header value: application} pairs.
-        The incoming "Host" request header is looked up in this dict,
-        and, if a match is found, the corresponding WSGI application
-        will be called instead of the default. Note that you often need
-        separate entries for "example.com" and "www.example.com".
-        In addition, "Host" headers may contain the port number.
-    """
-    
-    def __init__(self, default, domains=None, use_x_forwarded_host=True):
-        self.default = default
-        self.domains = domains or {}
-        self.use_x_forwarded_host = use_x_forwarded_host
-    
-    def __call__(self, environ, start_response):
-        domain = environ.get('HTTP_HOST', '')
-        if self.use_x_forwarded_host:
-            domain = environ.get("HTTP_X_FORWARDED_HOST", domain)
-        
-        nextapp = self.domains.get(domain)
-        if nextapp is None:
-            nextapp = self.default
-        return nextapp(environ, start_response)
-
-
-class InternalRedirector(object):
-    """WSGI middleware that handles raised cherrypy.InternalRedirect."""
-    
-    def __init__(self, nextapp, recursive=False):
-        self.nextapp = nextapp
-        self.recursive = recursive
-    
-    def __call__(self, environ, start_response):
-        redirections = []
-        while True:
-            environ = environ.copy()
-            try:
-                return self.nextapp(environ, start_response)
-            except _cherrypy.InternalRedirect, ir:
-                sn = environ.get('SCRIPT_NAME', '')
-                path = environ.get('PATH_INFO', '')
-                qs = environ.get('QUERY_STRING', '')
-                
-                # Add the *previous* path_info + qs to redirections.
-                old_uri = sn + path
-                if qs:
-                    old_uri += "?" + qs
-                redirections.append(old_uri)
-                
-                if not self.recursive:
-                    # Check to see if the new URI has been redirected to already
-                    new_uri = sn + ir.path
-                    if ir.query_string:
-                        new_uri += "?" + ir.query_string
-                    if new_uri in redirections:
-                        ir.request.close()
-                        raise RuntimeError("InternalRedirector visited the "
-                                           "same URL twice: %r" % new_uri)
-                
-                # Munge the environment and try again.
-                environ['REQUEST_METHOD'] = "GET"
-                environ['PATH_INFO'] = ir.path
-                environ['QUERY_STRING'] = ir.query_string
-                environ['wsgi.input'] = StringIO()
-                environ['CONTENT_LENGTH'] = "0"
-                environ['cherrypy.previous_request'] = ir.request
-
-
-class ExceptionTrapper(object):
-    
-    def __init__(self, nextapp, throws=(KeyboardInterrupt, SystemExit)):
-        self.nextapp = nextapp
-        self.throws = throws
-    
-    def __call__(self, environ, start_response):
-        return _TrappedResponse(self.nextapp, environ, start_response, self.throws)
-
-
-class _TrappedResponse(object):
-    
-    response = iter([])
-    
-    def __init__(self, nextapp, environ, start_response, throws):
-        self.nextapp = nextapp
-        self.environ = environ
-        self.start_response = start_response
-        self.throws = throws
-        self.started_response = False
-        self.response = self.trap(self.nextapp, self.environ, self.start_response)
-        self.iter_response = iter(self.response)
-    
-    def __iter__(self):
-        self.started_response = True
-        return self
-    
-    def next(self):
-        return self.trap(self.iter_response.next)
-    
-    def close(self):
-        if hasattr(self.response, 'close'):
-            self.response.close()
-    
-    def trap(self, func, *args, **kwargs):
-        try:
-            return func(*args, **kwargs)
-        except self.throws:
-            raise
-        except StopIteration:
-            raise
-        except:
-            tb = _cperror.format_exc()
-            #print('trapped (started %s):' % self.started_response, tb)
-            _cherrypy.log(tb, severity=40)
-            if not _cherrypy.request.show_tracebacks:
-                tb = ""
-            s, h, b = _cperror.bare_error(tb)
-            if self.started_response:
-                # Empty our iterable (so future calls raise StopIteration)
-                self.iter_response = iter([])
-            else:
-                self.iter_response = iter(b)
-            
-            try:
-                self.start_response(s, h, _sys.exc_info())
-            except:
-                # "The application must not trap any exceptions raised by
-                # start_response, if it called start_response with exc_info.
-                # Instead, it should allow such exceptions to propagate
-                # back to the server or gateway."
-                # But we still log and call close() to clean up ourselves.
-                _cherrypy.log(traceback=True, severity=40)
-                raise
-            
-            if self.started_response:
-                return "".join(b)
-            else:
-                return b
-
-
-#                           WSGI-to-CP Adapter                           #
-
-
-class AppResponse(object):
-    """WSGI response iterable for CherryPy applications."""
-    
-    def __init__(self, environ, start_response, cpapp):
-        if environ.get(u'wsgi.version') == (u'u', 0):
-            environ = downgrade_wsgi_ux_to_1x(environ)
-        self.environ = environ
-        self.cpapp = cpapp
-        try:
-            self.run()
-        except:
-            self.close()
-            raise
-        r = _cherrypy.serving.response
-        self.iter_response = iter(r.body)
-        self.write = start_response(r.output_status, r.header_list)
-    
-    def __iter__(self):
-        return self
-    
-    def next(self):
-        return self.iter_response.next()
-    
-    def close(self):
-        """Close and de-reference the current request and response. (Core)"""
-        self.cpapp.release_serving()
-    
-    def run(self):
-        """Create a Request object using environ."""
-        env = self.environ.get
-        
-        local = httputil.Host('', int(env('SERVER_PORT', 80)),
-                           env('SERVER_NAME', ''))
-        remote = httputil.Host(env('REMOTE_ADDR', ''),
-                               int(env('REMOTE_PORT', -1)),
-                               env('REMOTE_HOST', ''))
-        scheme = env('wsgi.url_scheme')
-        sproto = env('ACTUAL_SERVER_PROTOCOL', "HTTP/1.1")
-        request, resp = self.cpapp.get_serving(local, remote, scheme, sproto)
-        
-        # LOGON_USER is served by IIS, and is the name of the
-        # user after having been mapped to a local account.
-        # Both IIS and Apache set REMOTE_USER, when possible.
-        request.login = env('LOGON_USER') or env('REMOTE_USER') or None
-        request.multithread = self.environ['wsgi.multithread']
-        request.multiprocess = self.environ['wsgi.multiprocess']
-        request.wsgi_environ = self.environ
-        request.prev = env('cherrypy.previous_request', None)
-        
-        meth = self.environ['REQUEST_METHOD']
-        
-        path = httputil.urljoin(self.environ.get('SCRIPT_NAME', ''),
-                                self.environ.get('PATH_INFO', ''))
-        qs = self.environ.get('QUERY_STRING', '')
-        rproto = self.environ.get('SERVER_PROTOCOL')
-        headers = self.translate_headers(self.environ)
-        rfile = self.environ['wsgi.input']
-        request.run(meth, path, qs, rproto, headers, rfile)
-    
-    headerNames = {'HTTP_CGI_AUTHORIZATION': 'Authorization',
-                   'CONTENT_LENGTH': 'Content-Length',
-                   'CONTENT_TYPE': 'Content-Type',
-                   'REMOTE_HOST': 'Remote-Host',
-                   'REMOTE_ADDR': 'Remote-Addr',
-                   }
-    
-    def translate_headers(self, environ):
-        """Translate CGI-environ header names to HTTP header names."""
-        for cgiName in environ:
-            # We assume all incoming header keys are uppercase already.
-            if cgiName in self.headerNames:
-                yield self.headerNames[cgiName], environ[cgiName]
-            elif cgiName[:5] == "HTTP_":
-                # Hackish attempt at recovering original header names.
-                translatedHeader = cgiName[5:].replace("_", "-")
-                yield translatedHeader, environ[cgiName]
-
-
-class CPWSGIApp(object):
-    """A WSGI application object for a CherryPy Application.
-    
-    pipeline: a list of (name, wsgiapp) pairs. Each 'wsgiapp' MUST be a
-        constructor that takes an initial, positional 'nextapp' argument,
-        plus optional keyword arguments, and returns a WSGI application
-        (that takes environ and start_response arguments). The 'name' can
-        be any you choose, and will correspond to keys in self.config.
-    
-    head: rather than nest all apps in the pipeline on each call, it's only
-        done the first time, and the result is memoized into self.head. Set
-        this to None again if you change self.pipeline after calling self.
-    
-    config: a dict whose keys match names listed in the pipeline. Each
-        value is a further dict which will be passed to the corresponding
-        named WSGI callable (from the pipeline) as keyword arguments.
-    """
-    
-    pipeline = [('ExceptionTrapper', ExceptionTrapper),
-                ('InternalRedirector', InternalRedirector),
-                ]
-    head = None
-    config = {}
-    
-    response_class = AppResponse
-    
-    def __init__(self, cpapp, pipeline=None):
-        self.cpapp = cpapp
-        self.pipeline = self.pipeline[:]
-        if pipeline:
-            self.pipeline.extend(pipeline)
-        self.config = self.config.copy()
-    
-    def tail(self, environ, start_response):
-        """WSGI application callable for the actual CherryPy application.
-        
-        You probably shouldn't call this; call self.__call__ instead,
-        so that any WSGI middleware in self.pipeline can run first.
-        """
-        return self.response_class(environ, start_response, self.cpapp)
-    
-    def __call__(self, environ, start_response):
-        head = self.head
-        if head is None:
-            # Create and nest the WSGI apps in our pipeline (in reverse order).
-            # Then memoize the result in self.head.
-            head = self.tail
-            for name, callable in self.pipeline[::-1]:
-                conf = self.config.get(name, {})
-                head = callable(head, **conf)
-            self.head = head
-        return head(environ, start_response)
-    
-    def namespace_handler(self, k, v):
-        """Config handler for the 'wsgi' namespace."""
-        if k == "pipeline":
-            # Note this allows multiple 'wsgi.pipeline' config entries
-            # (but each entry will be processed in a 'random' order).
-            # It should also allow developers to set default middleware
-            # in code (passed to self.__init__) that deployers can add to
-            # (but not remove) via config.
-            self.pipeline.extend(v)
-        elif k == "response_class":
-            self.response_class = v
-        else:
-            name, arg = k.split(".", 1)
-            bucket = self.config.setdefault(name, {})
-            bucket[arg] = v
-
--- a/bundled/cherrypy/cherrypy/_cpwsgi_server.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,62 +0,0 @@
-"""WSGI server interface (see PEP 333). This adds some CP-specific bits to
-the framework-agnostic wsgiserver package.
-"""
-import sys
-
-import cherrypy
-from cherrypy import wsgiserver
-
-
-class CPHTTPRequest(wsgiserver.HTTPRequest):
-    pass
-
-
-class CPHTTPConnection(wsgiserver.HTTPConnection):
-    pass
-
-
-class CPWSGIServer(wsgiserver.CherryPyWSGIServer):
-    """Wrapper for wsgiserver.CherryPyWSGIServer.
-    
-    wsgiserver has been designed to not reference CherryPy in any way,
-    so that it can be used in other frameworks and applications. Therefore,
-    we wrap it here, so we can set our own mount points from cherrypy.tree
-    and apply some attributes from config -> cherrypy.server -> wsgiserver.
-    """
-    
-    def __init__(self, server_adapter=cherrypy.server):
-        self.server_adapter = server_adapter
-        self.max_request_header_size = self.server_adapter.max_request_header_size or 0
-        self.max_request_body_size = self.server_adapter.max_request_body_size or 0
-        
-        server_name = (self.server_adapter.socket_host or
-                       self.server_adapter.socket_file or
-                       None)
-        
-        self.wsgi_version = self.server_adapter.wsgi_version
-        s = wsgiserver.CherryPyWSGIServer
-        s.__init__(self, server_adapter.bind_addr, cherrypy.tree,
-                   self.server_adapter.thread_pool,
-                   server_name,
-                   max = self.server_adapter.thread_pool_max,
-                   request_queue_size = self.server_adapter.socket_queue_size,
-                   timeout = self.server_adapter.socket_timeout,
-                   shutdown_timeout = self.server_adapter.shutdown_timeout,
-                   )
-        self.protocol = self.server_adapter.protocol_version
-        self.nodelay = self.server_adapter.nodelay
-        
-        ssl_module = self.server_adapter.ssl_module or 'pyopenssl'
-        if self.server_adapter.ssl_context:
-            adapter_class = wsgiserver.get_ssl_adapter_class(ssl_module)
-            self.ssl_adapter = adapter_class(
-                self.server_adapter.ssl_certificate,
-                self.server_adapter.ssl_private_key,
-                self.server_adapter.ssl_certificate_chain)
-            self.ssl_adapter.context = self.server_adapter.ssl_context
-        elif self.server_adapter.ssl_certificate:
-            adapter_class = wsgiserver.get_ssl_adapter_class(ssl_module)
-            self.ssl_adapter = adapter_class(
-                self.server_adapter.ssl_certificate,
-                self.server_adapter.ssl_private_key,
-                self.server_adapter.ssl_certificate_chain)
--- a/bundled/cherrypy/cherrypy/cherryd	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-#! /usr/bin/env python
-"""The CherryPy daemon."""
-
-import sys
-
-import cherrypy
-from cherrypy.process import plugins, servers
-
-
-def start(configfiles=None, daemonize=False, environment=None,
-          fastcgi=False, scgi=False, pidfile=None, imports=None):
-    """Subscribe all engine plugins and start the engine."""
-    sys.path = [''] + sys.path
-    for i in imports or []:
-        exec("import %s" % i)
-    
-    for c in configfiles or []:
-        cherrypy.config.update(c)
-        # If there's only one app mounted, merge config into it.
-        if len(cherrypy.tree.apps) == 1:
-            for app in cherrypy.tree.apps.values():
-                app.merge(c)
-    
-    engine = cherrypy.engine
-    
-    if environment is not None:
-        cherrypy.config.update({'environment': environment})
-    
-    # Only daemonize if asked to.
-    if daemonize:
-        # Don't print anything to stdout/sterr.
-        cherrypy.config.update({'log.screen': False})
-        plugins.Daemonizer(engine).subscribe()
-    
-    if pidfile:
-        plugins.PIDFile(engine, pidfile).subscribe()
-    
-    if hasattr(engine, "signal_handler"):
-        engine.signal_handler.subscribe()
-    if hasattr(engine, "console_control_handler"):
-        engine.console_control_handler.subscribe()
-    
-    if fastcgi and scgi:
-        # fastcgi and scgi aren't allowed together.
-        cherrypy.log.error("fastcgi and scgi aren't allowed together.", 'ENGINE')
-        sys.exit(1)
-    elif fastcgi or scgi:
-        # Turn off autoreload when using fastcgi or scgi.
-        cherrypy.config.update({'engine.autoreload_on': False})
-        # Turn off the default HTTP server (which is subscribed by default).
-        cherrypy.server.unsubscribe()
-        
-        addr = cherrypy.server.bind_addr
-        if fastcgi:
-            f = servers.FlupFCGIServer(application=cherrypy.tree,
-                                       bindAddress=addr)
-        else:
-            f = servers.FlupSCGIServer(application=cherrypy.tree,
-                                       bindAddress=addr)
-        s = servers.ServerAdapter(engine, httpserver=f, bind_addr=addr)
-        s.subscribe()
-    
-    # Always start the engine; this will start all other services
-    try:
-        engine.start()
-    except:
-        # Assume the error has been logged already via bus.log.
-        sys.exit(1)
-    else:
-        engine.block()
-
-
-if __name__ == '__main__':
-    from optparse import OptionParser
-    
-    p = OptionParser()
-    p.add_option('-c', '--config', action="append", dest='config',
-                 help="specify config file(s)")
-    p.add_option('-d', action="store_true", dest='daemonize',
-                 help="run the server as a daemon")
-    p.add_option('-e', '--environment', dest='environment', default=None,
-                 help="apply the given config environment")
-    p.add_option('-f', action="store_true", dest='fastcgi',
-                 help="start a fastcgi server instead of the default HTTP server")
-    p.add_option('-s', action="store_true", dest='scgi',
-                 help="start a scgi server instead of the default HTTP server")
-    p.add_option('-i', '--import', action="append", dest='imports',
-                 help="specify modules to import")
-    p.add_option('-p', '--pidfile', dest='pidfile', default=None,
-                 help="store the process id in the given file")
-    p.add_option('-P', '--Path', action="append", dest='Path',
-                 help="add the given paths to sys.path")
-    options, args = p.parse_args()
-    
-    if options.Path:
-        for p in options.Path:
-            sys.path.insert(0, p)
-    
-    start(options.config, options.daemonize,
-          options.environment, options.fastcgi, options.scgi, options.pidfile,
-          options.imports)
-
Binary file bundled/cherrypy/cherrypy/favicon.ico has changed
--- a/bundled/cherrypy/cherrypy/lib/__init__.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-"""CherryPy Library"""
-
-# Deprecated in CherryPy 3.2 -- remove in CherryPy 3.3
-from cherrypy.lib.reprconf import _Builder, unrepr, modules, attributes
-
-class file_generator(object):
-    """Yield the given input (a file object) in chunks (default 64k). (Core)"""
-    
-    def __init__(self, input, chunkSize=65536):
-        self.input = input
-        self.chunkSize = chunkSize
-    
-    def __iter__(self):
-        return self
-    
-    def __next__(self):
-        chunk = self.input.read(self.chunkSize)
-        if chunk:
-            return chunk
-        else:
-            self.input.close()
-            raise StopIteration()
-    next = __next__
-
-def file_generator_limited(fileobj, count, chunk_size=65536):
-    """Yield the given file object in chunks, stopping after `count`
-    bytes has been emitted.  Default chunk size is 64kB. (Core)
-    """
-    remaining = count
-    while remaining > 0:
-        chunk = fileobj.read(min(chunk_size, remaining))
-        chunklen = len(chunk)
-        if chunklen == 0:
-            return
-        remaining -= chunklen
-        yield chunk
-
-def set_vary_header(response, header_name):
-    "Add a Vary header to a response"
-    varies = response.headers.get("Vary", "")
-    varies = [x.strip() for x in varies.split(",") if x.strip()]
-    if header_name not in varies:
-        varies.append(header_name)
-    response.headers['Vary'] = ", ".join(varies)
--- a/bundled/cherrypy/cherrypy/lib/auth.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-import cherrypy
-from cherrypy.lib import httpauth
-
-
-def check_auth(users, encrypt=None, realm=None):
-    """If an authorization header contains credentials, return True, else False."""
-    request = cherrypy.serving.request
-    if 'authorization' in request.headers:
-        # make sure the provided credentials are correctly set
-        ah = httpauth.parseAuthorization(request.headers['authorization'])
-        if ah is None:
-            raise cherrypy.HTTPError(400, 'Bad Request')
-        
-        if not encrypt:
-            encrypt = httpauth.DIGEST_AUTH_ENCODERS[httpauth.MD5]
-        
-        if hasattr(users, '__call__'):
-            try:
-                # backward compatibility
-                users = users() # expect it to return a dictionary
-                
-                if not isinstance(users, dict):
-                    raise ValueError("Authentication users must be a dictionary")
-                
-                # fetch the user password
-                password = users.get(ah["username"], None)
-            except TypeError:
-                # returns a password (encrypted or clear text)
-                password = users(ah["username"])
-        else:
-            if not isinstance(users, dict):
-                raise ValueError("Authentication users must be a dictionary")
-            
-            # fetch the user password
-            password = users.get(ah["username"], None)
-        
-        # validate the authorization by re-computing it here
-        # and compare it with what the user-agent provided
-        if httpauth.checkResponse(ah, password, method=request.method,
-                                  encrypt=encrypt, realm=realm):
-            request.login = ah["username"]
-            return True
-        
-        request.login = False
-    return False
-
-def basic_auth(realm, users, encrypt=None, debug=False):
-    """If auth fails, raise 401 with a basic authentication header.
-    
-    realm: a string containing the authentication realm.
-    users: a dict of the form: {username: password} or a callable returning a dict.
-    encrypt: callable used to encrypt the password returned from the user-agent.
-             if None it defaults to a md5 encryption.
-    """
-    if check_auth(users, encrypt):
-        if debug:
-            cherrypy.log('Auth successful', 'TOOLS.BASIC_AUTH')
-        return
-    
-    # inform the user-agent this path is protected
-    cherrypy.serving.response.headers['www-authenticate'] = httpauth.basicAuth(realm)
-    
-    raise cherrypy.HTTPError(401, "You are not authorized to access that resource")
-
-def digest_auth(realm, users, debug=False):
-    """If auth fails, raise 401 with a digest authentication header.
-    
-    realm: a string containing the authentication realm.
-    users: a dict of the form: {username: password} or a callable returning a dict.
-    """
-    if check_auth(users, realm=realm):
-        if debug:
-            cherrypy.log('Auth successful', 'TOOLS.DIGEST_AUTH')
-        return
-    
-    # inform the user-agent this path is protected
-    cherrypy.serving.response.headers['www-authenticate'] = httpauth.digestAuth(realm)
-    
-    raise cherrypy.HTTPError(401, "You are not authorized to access that resource")
--- a/bundled/cherrypy/cherrypy/lib/auth_basic.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-# This file is part of CherryPy <http://www.cherrypy.org/>
-# -*- coding: utf-8 -*-
-# vim:ts=4:sw=4:expandtab:fileencoding=utf-8
-
-__doc__ = """Module auth_basic.py provides a CherryPy 3.x tool which implements
-the server-side of HTTP Basic Access Authentication, as described in RFC 2617.
-
-Example usage, using the built-in checkpassword_dict function which uses a dict
-as the credentials store:
-
-userpassdict = {'bird' : 'bebop', 'ornette' : 'wayout'}
-checkpassword = cherrypy.lib.auth_basic.checkpassword_dict(userpassdict)
-basic_auth = {'tools.auth_basic.on': True,
-              'tools.auth_basic.realm': 'earth',
-              'tools.auth_basic.checkpassword': checkpassword,
-}
-app_config = { '/' : basic_auth }
-"""
-
-__author__ = 'visteya'
-__date__ = 'April 2009'
-
-import binascii
-import base64
-import cherrypy
-
-
-def checkpassword_dict(user_password_dict):
-    """Returns a checkpassword function which checks credentials
-    against a dictionary of the form: {username : password}.
-
-    If you want a simple dictionary-based authentication scheme, use
-    checkpassword_dict(my_credentials_dict) as the value for the
-    checkpassword argument to basic_auth().
-    """
-    def checkpassword(realm, user, password):
-        p = user_password_dict.get(user)
-        return p and p == password or False
-
-    return checkpassword
-
-
-def basic_auth(realm, checkpassword, debug=False):
-    """basic_auth is a CherryPy tool which hooks at before_handler to perform
-    HTTP Basic Access Authentication, as specified in RFC 2617.
-
-    If the request has an 'authorization' header with a 'Basic' scheme, this
-    tool attempts to authenticate the credentials supplied in that header.  If
-    the request has no 'authorization' header, or if it does but the scheme is
-    not 'Basic', or if authentication fails, the tool sends a 401 response with
-    a 'WWW-Authenticate' Basic header.
-
-    Arguments:
-    realm: a string containing the authentication realm.
-
-    checkpassword: a callable which checks the authentication credentials.
-        Its signature is checkpassword(realm, username, password). where
-        username and password are the values obtained from the request's
-        'authorization' header.  If authentication succeeds, checkpassword
-        returns True, else it returns False.
-    """
-    
-    if '"' in realm:
-        raise ValueError('Realm cannot contain the " (quote) character.')
-    request = cherrypy.serving.request
-    
-    auth_header = request.headers.get('authorization')
-    if auth_header is not None:
-        try:
-            scheme, params = auth_header.split(' ', 1)
-            if scheme.lower() == 'basic':
-                # since CherryPy claims compability with Python 2.3, we must use
-                # the legacy API of base64
-                username_password = base64.decodestring(params)
-                username, password = username_password.split(':', 1)
-                if checkpassword(realm, username, password):
-                    if debug:
-                        cherrypy.log('Auth succeeded', 'TOOLS.AUTH_BASIC')
-                    request.login = username
-                    return # successful authentication
-        except (ValueError, binascii.Error): # split() error, base64.decodestring() error
-            raise cherrypy.HTTPError(400, 'Bad Request')
-    
-    # Respond with 401 status and a WWW-Authenticate header
-    cherrypy.serving.response.headers['www-authenticate'] = 'Basic realm="%s"' % realm
-    raise cherrypy.HTTPError(401, "You are not authorized to access that resource")
-
--- a/bundled/cherrypy/cherrypy/lib/auth_digest.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,358 +0,0 @@
-# This file is part of CherryPy <http://www.cherrypy.org/>
-# -*- coding: utf-8 -*-
-# vim:ts=4:sw=4:expandtab:fileencoding=utf-8
-
-__doc__ = """An implementation of the server-side of HTTP Digest Access
-Authentication, which is described in RFC 2617.
-
-Example usage, using the built-in get_ha1_dict_plain function which uses a dict
-of plaintext passwords as the credentials store:
-
-userpassdict = {'alice' : '4x5istwelve'}
-get_ha1 = cherrypy.lib.auth_digest.get_ha1_dict_plain(userpassdict)
-digest_auth = {'tools.auth_digest.on': True,
-               'tools.auth_digest.realm': 'wonderland',
-               'tools.auth_digest.get_ha1': get_ha1,
-               'tools.auth_digest.key': 'a565c27146791cfb',
-}
-app_config = { '/' : digest_auth }
-"""
-
-__author__ = 'visteya'
-__date__ = 'April 2009'
-
-
-try:
-    from hashlib import md5
-except ImportError:
-    # Python 2.4 and earlier
-    from md5 import new as md5
-md5_hex = lambda s: md5(s).hexdigest()
-
-import time
-import base64
-from urllib2 import parse_http_list, parse_keqv_list
-
-import cherrypy
-
-qop_auth = 'auth'
-qop_auth_int = 'auth-int'
-valid_qops = (qop_auth, qop_auth_int)
-
-valid_algorithms = ('MD5', 'MD5-sess')
-
-
-def TRACE(msg):
-    cherrypy.log(msg, context='TOOLS.AUTH_DIGEST')
-
-# Three helper functions for users of the tool, providing three variants
-# of get_ha1() functions for three different kinds of credential stores.
-def get_ha1_dict_plain(user_password_dict):
-    """Returns a get_ha1 function which obtains a plaintext password from a
-    dictionary of the form: {username : password}.
-
-    If you want a simple dictionary-based authentication scheme, with plaintext
-    passwords, use get_ha1_dict_plain(my_userpass_dict) as the value for the
-    get_ha1 argument to digest_auth().
-    """
-    def get_ha1(realm, username):
-        password = user_password_dict.get(username)
-        if password:
-            return md5_hex('%s:%s:%s' % (username, realm, password))
-        return None
-
-    return get_ha1
-
-def get_ha1_dict(user_ha1_dict):
-    """Returns a get_ha1 function which obtains a HA1 password hash from a
-    dictionary of the form: {username : HA1}.
-
-    If you want a dictionary-based authentication scheme, but with
-    pre-computed HA1 hashes instead of plain-text passwords, use
-    get_ha1_dict(my_userha1_dict) as the value for the get_ha1
-    argument to digest_auth().
-    """
-    def get_ha1(realm, username):
-        return user_ha1_dict.get(user)
-
-    return get_ha1
-
-def get_ha1_file_htdigest(filename):
-    """Returns a get_ha1 function which obtains a HA1 password hash from a
-    flat file with lines of the same format as that produced by the Apache
-    htdigest utility. For example, for realm 'wonderland', username 'alice',
-    and password '4x5istwelve', the htdigest line would be:
-
-    alice:wonderland:3238cdfe91a8b2ed8e39646921a02d4c
-
-    If you want to use an Apache htdigest file as the credentials store,
-    then use get_ha1_file_htdigest(my_htdigest_file) as the value for the
-    get_ha1 argument to digest_auth().  It is recommended that the filename
-    argument be an absolute path, to avoid problems.
-    """
-    def get_ha1(realm, username):
-        result = None
-        f = open(filename, 'r')
-        for line in f:
-            u, r, ha1 = line.rstrip().split(':')
-            if u == username and r == realm:
-                result = ha1
-                break
-        f.close()
-        return result
-
-    return get_ha1
-
-
-def synthesize_nonce(s, key, timestamp=None):
-    """Synthesize a nonce value which resists spoofing and can be checked for staleness.
-    Returns a string suitable as the value for 'nonce' in the www-authenticate header.
-
-    Args:
-    s: a string related to the resource, such as the hostname of the server.
-    key: a secret string known only to the server.
-    timestamp: an integer seconds-since-the-epoch timestamp
-    """
-    if timestamp is None:
-        timestamp = int(time.time())
-    h = md5_hex('%s:%s:%s' % (timestamp, s, key))
-    nonce = '%s:%s' % (timestamp, h)
-    return nonce
-
-
-def H(s):
-    """The hash function H"""
-    return md5_hex(s)
-
-
-class HttpDigestAuthorization (object):
-    """Class to parse a Digest Authorization header and perform re-calculation
-    of the digest.
-    """
-
-    def errmsg(self, s):
-        return 'Digest Authorization header: %s' % s
-
-    def __init__(self, auth_header, http_method, debug=False):
-        self.http_method = http_method
-        self.debug = debug
-        scheme, params  = auth_header.split(" ", 1)
-        self.scheme = scheme.lower()
-        if self.scheme != 'digest':
-            raise ValueError('Authorization scheme is not "Digest"')
-
-        self.auth_header = auth_header
-
-        # make a dict of the params
-        items = parse_http_list(params)
-        paramsd = parse_keqv_list(items)
-
-        self.realm = paramsd.get('realm')
-        self.username = paramsd.get('username')
-        self.nonce = paramsd.get('nonce')
-        self.uri = paramsd.get('uri')
-        self.method = paramsd.get('method')
-        self.response = paramsd.get('response') # the response digest
-        self.algorithm = paramsd.get('algorithm', 'MD5')
-        self.cnonce = paramsd.get('cnonce')
-        self.opaque = paramsd.get('opaque')
-        self.qop = paramsd.get('qop') # qop
-        self.nc = paramsd.get('nc') # nonce count
-
-        # perform some correctness checks
-        if self.algorithm not in valid_algorithms:
-            raise ValueError(self.errmsg("Unsupported value for algorithm: '%s'" % self.algorithm))
-
-        has_reqd = self.username and \
-                   self.realm and \
-                   self.nonce and \
-                   self.uri and \
-                   self.response
-        if not has_reqd:
-            raise ValueError(self.errmsg("Not all required parameters are present."))
-
-        if self.qop:
-            if self.qop not in valid_qops:
-                raise ValueError(self.errmsg("Unsupported value for qop: '%s'" % self.qop))
-            if not (self.cnonce and self.nc):
-                raise ValueError(self.errmsg("If qop is sent then cnonce and nc MUST be present"))
-        else:
-            if self.cnonce or self.nc:
-                raise ValueError(self.errmsg("If qop is not sent, neither cnonce nor nc can be present"))
-
-
-    def __str__(self):
-        return 'authorization : %s' % self.auth_header
-
-    def validate_nonce(self, s, key):
-        """Validate the nonce.
-        Returns True if nonce was generated by synthesize_nonce() and the timestamp
-        is not spoofed, else returns False.
-
-        Args:
-        s: a string related to the resource, such as the hostname of the server.
-        key: a secret string known only to the server.
-        Both s and key must be the same values which were used to synthesize the nonce
-        we are trying to validate.
-        """
-        try:
-            timestamp, hashpart = self.nonce.split(':', 1)
-            s_timestamp, s_hashpart = synthesize_nonce(s, key, timestamp).split(':', 1)
-            is_valid = s_hashpart == hashpart
-            if self.debug:
-                TRACE('validate_nonce: %s' % is_valid)
-            return is_valid
-        except ValueError: # split() error
-            pass
-        return False
-
-
-    def is_nonce_stale(self, max_age_seconds=600):
-        """Returns True if a validated nonce is stale.  The nonce contains a
-        timestamp in plaintext and also a secure hash of the timestamp.  You should
-        first validate the nonce to ensure the plaintext timestamp is not spoofed.
-        """
-        try:
-            timestamp, hashpart = self.nonce.split(':', 1)
-            if int(timestamp) + max_age_seconds > int(time.time()):
-                return False
-        except ValueError: # int() error
-            pass
-        if self.debug:
-            TRACE("nonce is stale")
-        return True
-
-
-    def HA2(self, entity_body=''):
-        """Returns the H(A2) string.  See RFC 2617 3.2.2.3."""
-        # RFC 2617 3.2.2.3
-        # If the "qop" directive's value is "auth" or is unspecified, then A2 is:
-        #    A2 = method ":" digest-uri-value
-        #
-        # If the "qop" value is "auth-int", then A2 is:
-        #    A2 = method ":" digest-uri-value ":" H(entity-body)
-        if self.qop is None or self.qop == "auth":
-            a2 = '%s:%s' % (self.http_method, self.uri)
-        elif self.qop == "auth-int":
-            a2 = "%s:%s:%s" % (self.http_method, self.uri, H(entity_body))
-        else:
-            # in theory, this should never happen, since I validate qop in __init__()
-            raise ValueError(self.errmsg("Unrecognized value for qop!"))
-        return H(a2)
-
-
-    def request_digest(self, ha1, entity_body=''):
-        """Calculates the Request-Digest.  See RFC 2617 3.2.2.1.
-        Arguments:
-
-        ha1 : the HA1 string obtained from the credentials store.
-
-        entity_body : if 'qop' is set to 'auth-int', then A2 includes a hash
-            of the "entity body".  The entity body is the part of the
-            message which follows the HTTP headers.  See RFC 2617 section
-            4.3.  This refers to the entity the user agent sent in the request which
-            has the Authorization header.  Typically GET requests don't have an entity,
-            and POST requests do.
-        """
-        ha2 = self.HA2(entity_body)
-        # Request-Digest -- RFC 2617 3.2.2.1
-        if self.qop:
-            req = "%s:%s:%s:%s:%s" % (self.nonce, self.nc, self.cnonce, self.qop, ha2)
-        else:
-            req = "%s:%s" % (self.nonce, ha2)
-
-        # RFC 2617 3.2.2.2
-        #
-        # If the "algorithm" directive's value is "MD5" or is unspecified, then A1 is:
-        # A1 = unq(username-value) ":" unq(realm-value) ":" passwd
-        #
-        # If the "algorithm" directive's value is "MD5-sess", then A1 is
-        # calculated only once - on the first request by the client following
-        # receipt of a WWW-Authenticate challenge from the server.
-        # A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd )
-        #         ":" unq(nonce-value) ":" unq(cnonce-value)
-        if self.algorithm == 'MD5-sess':
-            ha1 = H('%s:%s:%s' % (ha1, self.nonce, self.cnonce))
-
-        digest = H('%s:%s' % (ha1, req))
-        return digest
-
-
-
-def www_authenticate(realm, key, algorithm='MD5', nonce=None, qop=qop_auth, stale=False):
-    """Constructs a WWW-Authenticate header for Digest authentication."""
-    if qop not in valid_qops:
-        raise ValueError("Unsupported value for qop: '%s'" % qop)
-    if algorithm not in valid_algorithms:
-        raise ValueError("Unsupported value for algorithm: '%s'" % algorithm)
-
-    if nonce is None:
-        nonce = synthesize_nonce(realm, key)
-    s = 'Digest realm="%s", nonce="%s", algorithm="%s", qop="%s"' % (
-                realm, nonce, algorithm, qop)
-    if stale:
-        s += ', stale="true"'
-    return s
-
-
-def digest_auth(realm, get_ha1, key, debug=False):
-    """digest_auth is a CherryPy tool which hooks at before_handler to perform
-    HTTP Digest Access Authentication, as specified in RFC 2617.
-    
-    If the request has an 'authorization' header with a 'Digest' scheme, this
-    tool authenticates the credentials supplied in that header.  If
-    the request has no 'authorization' header, or if it does but the scheme is
-    not "Digest", or if authentication fails, the tool sends a 401 response with
-    a 'WWW-Authenticate' Digest header.
-    
-    Arguments:
-    realm: a string containing the authentication realm.
-    
-    get_ha1: a callable which looks up a username in a credentials store
-        and returns the HA1 string, which is defined in the RFC to be
-        MD5(username : realm : password).  The function's signature is:
-            get_ha1(realm, username)
-        where username is obtained from the request's 'authorization' header.
-        If username is not found in the credentials store, get_ha1() returns
-        None.
-    
-    key: a secret string known only to the server, used in the synthesis of nonces.
-    """
-    request = cherrypy.serving.request
-    
-    auth_header = request.headers.get('authorization')
-    nonce_is_stale = False
-    if auth_header is not None:
-        try:
-            auth = HttpDigestAuthorization(auth_header, request.method, debug=debug)
-        except ValueError, e:
-            raise cherrypy.HTTPError(400, 'Bad Request: %s' % e)
-        
-        if debug:
-            TRACE(str(auth))
-        
-        if auth.validate_nonce(realm, key):
-            ha1 = get_ha1(realm, auth.username)
-            if ha1 is not None:
-                # note that for request.body to be available we need to hook in at
-                # before_handler, not on_start_resource like 3.1.x digest_auth does.
-                digest = auth.request_digest(ha1, entity_body=request.body)
-                if digest == auth.response: # authenticated
-                    if debug:
-                        TRACE("digest matches auth.response")
-                    # Now check if nonce is stale.
-                    # The choice of ten minutes' lifetime for nonce is somewhat arbitrary
-                    nonce_is_stale = auth.is_nonce_stale(max_age_seconds=600)
-                    if not nonce_is_stale:
-                        request.login = auth.username
-                        if debug:
-                            TRACE("authentication of %s successful" % auth.username)
-                        return
-    
-    # Respond with 401 status and a WWW-Authenticate header
-    header = www_authenticate(realm, key, stale=nonce_is_stale)
-    if debug:
-        TRACE(header)
-    cherrypy.serving.response.headers['WWW-Authenticate'] = header
-    raise cherrypy.HTTPError(401, "You are not authorized to access that resource")
-
--- a/bundled/cherrypy/cherrypy/lib/caching.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,401 +0,0 @@
-import datetime
-import threading
-import time
-
-import cherrypy
-from cherrypy.lib import cptools, httputil
-
-
-class Cache(object):
-    
-    def get(self):
-        raise NotImplemented
-    
-    def put(self, obj, size):
-        raise NotImplemented
-    
-    def delete(self):
-        raise NotImplemented
-    
-    def clear(self):
-        raise NotImplemented
-
-
-
-# ------------------------------- Memory Cache ------------------------------- #
-
-
-class AntiStampedeCache(dict):
-    
-    def wait(self, key, timeout=5, debug=False):
-        """Return the cached value for the given key, or None.
-        
-        If timeout is not None (the default), and the value is already
-        being calculated by another thread, wait until the given timeout has
-        elapsed. If the value is available before the timeout expires, it is
-        returned. If not, None is returned, and a sentinel placed in the cache
-        to signal other threads to wait.
-        
-        If timeout is None, no waiting is performed nor sentinels used.
-        """
-        value = self.get(key)
-        if isinstance(value, threading._Event):
-            if timeout is None:
-                # Ignore the other thread and recalc it ourselves.
-                if debug:
-                    cherrypy.log('No timeout', 'TOOLS.CACHING')
-                return None
-            
-            # Wait until it's done or times out.
-            if debug:
-                cherrypy.log('Waiting up to %s seconds' % timeout, 'TOOLS.CACHING')
-            value.wait(timeout)
-            if value.result is not None:
-                # The other thread finished its calculation. Use it.
-                if debug:
-                    cherrypy.log('Result!', 'TOOLS.CACHING')
-                return value.result
-            # Timed out. Stick an Event in the slot so other threads wait
-            # on this one to finish calculating the value.
-            if debug:
-                cherrypy.log('Timed out', 'TOOLS.CACHING')
-            e = threading.Event()
-            e.result = None
-            dict.__setitem__(self, key, e)
-            
-            return None
-        elif value is None:
-            # Stick an Event in the slot so other threads wait
-            # on this one to finish calculating the value.
-            if debug:
-                cherrypy.log('Timed out', 'TOOLS.CACHING')
-            e = threading.Event()
-            e.result = None
-            dict.__setitem__(self, key, e)
-        return value
-    
-    def __setitem__(self, key, value):
-        """Set the cached value for the given key."""
-        existing = self.get(key)
-        dict.__setitem__(self, key, value)
-        if isinstance(existing, threading._Event):
-            # Set Event.result so other threads waiting on it have
-            # immediate access without needing to poll the cache again.
-            existing.result = value
-            existing.set()
-
-
-class MemoryCache(Cache):
-    """An in-memory cache for varying response content.
-    
-    Each key in self.store is a URI, and each value is an AntiStampedeCache.
-    The response for any given URI may vary based on the values of
-    "selecting request headers"; that is, those named in the Vary
-    response header. We assume the list of header names to be constant
-    for each URI throughout the lifetime of the application, and store
-    that list in self.store[uri].selecting_headers.
-    
-    The items contained in self.store[uri] have keys which are tuples of request
-    header values (in the same order as the names in its selecting_headers),
-    and values which are the actual responses.
-    """
-    
-    maxobjects = 1000
-    maxobj_size = 100000
-    maxsize = 10000000
-    delay = 600
-    antistampede_timeout = 5
-    expire_freq = 0.1
-    debug = False
-    
-    def __init__(self):
-        self.clear()
-        
-        # Run self.expire_cache in a separate daemon thread.
-        t = threading.Thread(target=self.expire_cache, name='expire_cache')
-        self.expiration_thread = t
-        if hasattr(threading.Thread, "daemon"):
-            # Python 2.6+
-            t.daemon = True
-        else:
-            t.setDaemon(True)
-        t.start()
-    
-    def clear(self):
-        """Reset the cache to its initial, empty state."""
-        self.store = {}
-        self.expirations = {}
-        self.tot_puts = 0
-        self.tot_gets = 0
-        self.tot_hist = 0
-        self.tot_expires = 0
-        self.tot_non_modified = 0
-        self.cursize = 0
-    
-    def expire_cache(self):
-        # expire_cache runs in a separate thread which the servers are
-        # not aware of. It's possible that "time" will be set to None
-        # arbitrarily, so we check "while time" to avoid exceptions.
-        # See tickets #99 and #180 for more information.
-        while time:
-            now = time.time()
-            # Must make a copy of expirations so it doesn't change size
-            # during iteration
-            for expiration_time, objects in self.expirations.items():
-                if expiration_time <= now:
-                    for obj_size, uri, sel_header_values in objects:
-                        try:
-                            del self.store[uri][sel_header_values]
-                            self.tot_expires += 1
-                            self.cursize -= obj_size
-                        except KeyError:
-                            # the key may have been deleted elsewhere
-                            pass
-                    del self.expirations[expiration_time]
-            time.sleep(self.expire_freq)
-    
-    def get(self):
-        """Return the current variant if in the cache, else None."""
-        request = cherrypy.serving.request
-        self.tot_gets += 1
-        
-        uri = cherrypy.url(qs=request.query_string)
-        uricache = self.store.get(uri)
-        if uricache is None:
-            return None
-        
-        header_values = [request.headers.get(h, '')
-                         for h in uricache.selecting_headers]
-        header_values.sort()
-        variant = uricache.wait(key=tuple(header_values),
-                                timeout=self.antistampede_timeout,
-                                debug=self.debug)
-        if variant is not None:
-            self.tot_hist += 1
-        return variant
-    
-    def put(self, variant, size):
-        """Store the current variant in the cache."""
-        request = cherrypy.serving.request
-        response = cherrypy.serving.response
-        
-        uri = cherrypy.url(qs=request.query_string)
-        uricache = self.store.get(uri)
-        if uricache is None:
-            uricache = AntiStampedeCache()
-            uricache.selecting_headers = [
-                e.value for e in response.headers.elements('Vary')]
-            self.store[uri] = uricache
-        
-        if len(self.store) < self.maxobjects:
-            total_size = self.cursize + size
-            
-            # checks if there's space for the object
-            if (size < self.maxobj_size and total_size < self.maxsize):
-                # add to the expirations list
-                expiration_time = response.time + self.delay
-                bucket = self.expirations.setdefault(expiration_time, [])
-                bucket.append((size, uri, uricache.selecting_headers))
-                
-                # add to the cache
-                header_values = [request.headers.get(h, '')
-                                 for h in uricache.selecting_headers]
-                header_values.sort()
-                uricache[tuple(header_values)] = variant
-                self.tot_puts += 1
-                self.cursize = total_size
-    
-    def delete(self):
-        """Remove ALL cached variants of the current resource."""
-        uri = cherrypy.url(qs=cherrypy.serving.request.query_string)
-        self.store.pop(uri, None)
-
-
-def get(invalid_methods=("POST", "PUT", "DELETE"), debug=False, **kwargs):
-    """Try to obtain cached output. If fresh enough, raise HTTPError(304).
-    
-    If POST, PUT, or DELETE:
-        * invalidates (deletes) any cached response for this resource
-        * sets request.cached = False
-        * sets request.cacheable = False
-    
-    else if a cached copy exists:
-        * sets request.cached = True
-        * sets request.cacheable = False
-        * sets response.headers to the cached values
-        * checks the cached Last-Modified response header against the
-            current If-(Un)Modified-Since request headers; raises 304
-            if necessary.
-        * sets response.status and response.body to the cached values
-        * returns True
-    
-    otherwise:
-        * sets request.cached = False
-        * sets request.cacheable = True
-        * returns False
-    """
-    request = cherrypy.serving.request
-    response = cherrypy.serving.response
-    
-    if not hasattr(cherrypy, "_cache"):
-        # Make a process-wide Cache object.
-        cherrypy._cache = kwargs.pop("cache_class", MemoryCache)()
-        
-        # Take all remaining kwargs and set them on the Cache object.
-        for k, v in kwargs.items():
-            setattr(cherrypy._cache, k, v)
-        cherrypy._cache.debug = debug
-    
-    # POST, PUT, DELETE should invalidate (delete) the cached copy.
-    # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.10.
-    if request.method in invalid_methods:
-        if debug:
-            cherrypy.log('request.method %r in invalid_methods %r' %
-                         (request.method, invalid_methods), 'TOOLS.CACHING')
-        cherrypy._cache.delete()
-        request.cached = False
-        request.cacheable = False
-        return False
-    
-    if 'no-cache' in [e.value for e in request.headers.elements('Pragma')]:
-        request.cached = False
-        request.cacheable = True
-        return False
-    
-    cache_data = cherrypy._cache.get()
-    request.cached = bool(cache_data)
-    request.cacheable = not request.cached
-    if request.cached:
-        # Serve the cached copy.
-        max_age = cherrypy._cache.delay
-        for v in [e.value for e in request.headers.elements('Cache-Control')]:
-            atoms = v.split('=', 1)
-            directive = atoms.pop(0)
-            if directive == 'max-age':
-                if len(atoms) != 1 or not atoms[0].isdigit():
-                    raise cherrypy.HTTPError(400, "Invalid Cache-Control header")
-                max_age = int(atoms[0])
-                break
-            elif directive == 'no-cache':
-                if debug:
-                    cherrypy.log('Ignoring cache due to Cache-Control: no-cache',
-                                 'TOOLS.CACHING')
-                request.cached = False
-                request.cacheable = True
-                return False
-        
-        if debug:
-            cherrypy.log('Reading response from cache', 'TOOLS.CACHING')
-        s, h, b, create_time = cache_data
-        age = int(response.time - create_time)
-        if (age > max_age):
-            if debug:
-                cherrypy.log('Ignoring cache due to age > %d' % max_age,
-                             'TOOLS.CACHING')
-            request.cached = False
-            request.cacheable = True
-            return False
-        
-        # Copy the response headers. See http://www.cherrypy.org/ticket/721.
-        response.headers = rh = httputil.HeaderMap()
-        for k in h:
-            dict.__setitem__(rh, k, dict.__getitem__(h, k))
-        
-        # Add the required Age header
-        response.headers["Age"] = str(age)
-        
-        try:
-            # Note that validate_since depends on a Last-Modified header;
-            # this was put into the cached copy, and should have been
-            # resurrected just above (response.headers = cache_data[1]).
-            cptools.validate_since()
-        except cherrypy.HTTPRedirect, x:
-            if x.status == 304:
-                cherrypy._cache.tot_non_modified += 1
-            raise
-        
-        # serve it & get out from the request
-        response.status = s
-        response.body = b
-    else:
-        if debug:
-            cherrypy.log('request is not cached', 'TOOLS.CACHING')
-    return request.cached
-
-
-def tee_output():
-    request = cherrypy.serving.request
-    if 'no-store' in request.headers.values('Cache-Control'):
-        return
-    
-    def tee(body):
-        """Tee response.body into a list."""
-        if ('no-cache' in response.headers.values('Pragma') or
-            'no-store' in response.headers.values('Cache-Control')):
-            for chunk in body:
-                yield chunk
-            return
-        
-        output = []
-        for chunk in body:
-            output.append(chunk)
-            yield chunk
-        
-        # save the cache data
-        body = ''.join(output)
-        cherrypy._cache.put((response.status, response.headers or {},
-                             body, response.time), len(body))
-    
-    response = cherrypy.serving.response
-    response.body = tee(response.body)
-
-
-def expires(secs=0, force=False, debug=False):
-    """Tool for influencing cache mechanisms using the 'Expires' header.
-    
-    'secs' must be either an int or a datetime.timedelta, and indicates the
-    number of seconds between response.time and when the response should
-    expire. The 'Expires' header will be set to (response.time + secs).
-    
-    If 'secs' is zero, the 'Expires' header is set one year in the past, and
-    the following "cache prevention" headers are also set:
-       'Pragma': 'no-cache'
-       'Cache-Control': 'no-cache, must-revalidate'
-    
-    If 'force' is False (the default), the following headers are checked:
-    'Etag', 'Last-Modified', 'Age', 'Expires'. If any are already present,
-    none of the above response headers are set.
-    """
-    
-    response = cherrypy.serving.response
-    headers = response.headers
-    
-    cacheable = False
-    if not force:
-        # some header names that indicate that the response can be cached
-        for indicator in ('Etag', 'Last-Modified', 'Age', 'Expires'):
-            if indicator in headers:
-                cacheable = True
-                break
-    
-    if not cacheable and not force:
-        if debug:
-            cherrypy.log('request is not cacheable', 'TOOLS.EXPIRES')
-    else:
-        if debug:
-            cherrypy.log('request is cacheable', 'TOOLS.EXPIRES')
-        if isinstance(secs, datetime.timedelta):
-            secs = (86400 * secs.days) + secs.seconds
-        
-        if secs == 0:
-            if force or ("Pragma" not in headers):
-                headers["Pragma"] = "no-cache"
-            if cherrypy.serving.request.protocol >= (1, 1):
-                if force or "Cache-Control" not in headers:
-                    headers["Cache-Control"] = "no-cache, must-revalidate"
-            # Set an explicit Expires date in the past.
-            expiry = httputil.HTTPDate(1169942400.0)
-        else:
-            expiry = httputil.HTTPDate(response.time + secs)
-        if force or "Expires" not in headers:
-            headers["Expires"] = expiry
--- a/bundled/cherrypy/cherrypy/lib/covercp.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,364 +0,0 @@
-"""Code-coverage tools for CherryPy.
-
-To use this module, or the coverage tools in the test suite,
-you need to download 'coverage.py', either Gareth Rees' original
-implementation:
-http://www.garethrees.org/2001/12/04/python-coverage/
-
-or Ned Batchelder's enhanced version:
-http://www.nedbatchelder.com/code/modules/coverage.html
-
-To turn on coverage tracing, use the following code:
-
-    cherrypy.engine.subscribe('start', covercp.start)
-
-DO NOT subscribe anything on the 'start_thread' channel, as previously
-recommended. Calling start once in the main thread should be sufficient
-to start coverage on all threads. Calling start again in each thread
-effectively clears any coverage data gathered up to that point.
-
-Run your code, then use the covercp.serve() function to browse the
-results in a web browser. If you run this module from the command line,
-it will call serve() for you.
-"""
-
-import re
-import sys
-import cgi
-from urllib import quote_plus
-import os, os.path
-localFile = os.path.join(os.path.dirname(__file__), "coverage.cache")
-
-try:
-    from coverage import the_coverage as coverage
-    def start():
-        coverage.start()
-except ImportError:
-    # Setting coverage to None will raise errors
-    # that need to be trapped downstream.
-    coverage = None
-    
-    import warnings
-    warnings.warn("No code coverage will be performed; coverage.py could not be imported.")
-    
-    def start():
-        pass
-start.priority = 20
-
-TEMPLATE_MENU = """<html>
-<head>
-    <title>CherryPy Coverage Menu</title>
-    <style>
-        body {font: 9pt Arial, serif;}
-        #tree {
-            font-size: 8pt;
-            font-family: Andale Mono, monospace;
-            white-space: pre;
-            }
-        #tree a:active, a:focus {
-            background-color: black;
-            padding: 1px;
-            color: white;
-            border: 0px solid #9999FF;
-            -moz-outline-style: none;
-            }
-        .fail { color: red;}
-        .pass { color: #888;}
-        #pct { text-align: right;}
-        h3 {
-            font-size: small;
-            font-weight: bold;
-            font-style: italic;
-            margin-top: 5px; 
-            }
-        input { border: 1px solid #ccc; padding: 2px; }
-        .directory {
-            color: #933;
-            font-style: italic;
-            font-weight: bold;
-            font-size: 10pt;
-            }
-        .file {
-            color: #400;
-            }
-        a { text-decoration: none; }
-        #crumbs {
-            color: white;
-            font-size: 8pt;
-            font-family: Andale Mono, monospace;
-            width: 100%;
-            background-color: black;
-            }
-        #crumbs a {
-            color: #f88;
-            }
-        #options {
-            line-height: 2.3em;
-            border: 1px solid black;
-            background-color: #eee;
-            padding: 4px;
-            }
-        #exclude {
-            width: 100%;
-            margin-bottom: 3px;
-            border: 1px solid #999;
-            }
-        #submit {
-            background-color: black;
-            color: white;
-            border: 0;
-            margin-bottom: -9px;
-            }
-    </style>
-</head>
-<body>
-<h2>CherryPy Coverage</h2>"""
-
-TEMPLATE_FORM = """
-<div id="options">
-<form action='menu' method=GET>
-    <input type='hidden' name='base' value='%(base)s' />
-    Show percentages <input type='checkbox' %(showpct)s name='showpct' value='checked' /><br />
-    Hide files over <input type='text' id='pct' name='pct' value='%(pct)s' size='3' />%%<br />
-    Exclude files matching<br />
-    <input type='text' id='exclude' name='exclude' value='%(exclude)s' size='20' />
-    <br />
-
-    <input type='submit' value='Change view' id="submit"/>
-</form>
-</div>""" 
-
-TEMPLATE_FRAMESET = """<html>
-<head><title>CherryPy coverage data</title></head>
-<frameset cols='250, 1*'>
-    <frame src='menu?base=%s' />
-    <frame name='main' src='' />
-</frameset>
-</html>
-"""
-
-TEMPLATE_COVERAGE = """<html>
-<head>
-    <title>Coverage for %(name)s</title>
-    <style>
-        h2 { margin-bottom: .25em; }
-        p { margin: .25em; }
-        .covered { color: #000; background-color: #fff; }
-        .notcovered { color: #fee; background-color: #500; }
-        .excluded { color: #00f; background-color: #fff; }
-         table .covered, table .notcovered, table .excluded
-             { font-family: Andale Mono, monospace;
-               font-size: 10pt; white-space: pre; }
-
-         .lineno { background-color: #eee;}
-         .notcovered .lineno { background-color: #000;}
-         table { border-collapse: collapse;
-    </style>
-</head>
-<body>
-<h2>%(name)s</h2>
-<p>%(fullpath)s</p>
-<p>Coverage: %(pc)s%%</p>"""
-
-TEMPLATE_LOC_COVERED = """<tr class="covered">
-    <td class="lineno">%s&nbsp;</td>
-    <td>%s</td>
-</tr>\n"""
-TEMPLATE_LOC_NOT_COVERED = """<tr class="notcovered">
-    <td class="lineno">%s&nbsp;</td>
-    <td>%s</td>
-</tr>\n"""
-TEMPLATE_LOC_EXCLUDED = """<tr class="excluded">
-    <td class="lineno">%s&nbsp;</td>
-    <td>%s</td>
-</tr>\n"""
-
-TEMPLATE_ITEM = "%s%s<a class='file' href='report?name=%s' target='main'>%s</a>\n"
-
-def _percent(statements, missing):
-    s = len(statements)
-    e = s - len(missing)
-    if s > 0:
-        return int(round(100.0 * e / s))
-    return 0
-
-def _show_branch(root, base, path, pct=0, showpct=False, exclude=""):
-    
-    # Show the directory name and any of our children
-    dirs = [k for k, v in root.items() if v]
-    dirs.sort()
-    for name in dirs:
-        newpath = os.path.join(path, name)
-        
-        if newpath.lower().startswith(base):
-            relpath = newpath[len(base):]
-            yield "| " * relpath.count(os.sep)
-            yield "<a class='directory' href='menu?base=%s&exclude=%s'>%s</a>\n" % \
-                   (newpath, quote_plus(exclude), name)
-        
-        for chunk in _show_branch(root[name], base, newpath, pct, showpct, exclude):
-            yield chunk
-    
-    # Now list the files
-    if path.lower().startswith(base):
-        relpath = path[len(base):]
-        files = [k for k, v in root.items() if not v]
-        files.sort()
-        for name in files:
-            newpath = os.path.join(path, name)
-            
-            pc_str = ""
-            if showpct:
-                try:
-                    _, statements, _, missing, _ = coverage.analysis2(newpath)
-                except:
-                    # Yes, we really want to pass on all errors.
-                    pass
-                else:
-                    pc = _percent(statements, missing)
-                    pc_str = ("%3d%% " % pc).replace(' ','&nbsp;')
-                    if pc < float(pct) or pc == -1:
-                        pc_str = "<span class='fail'>%s</span>" % pc_str
-                    else:
-                        pc_str = "<span class='pass'>%s</span>" % pc_str
-            
-            yield TEMPLATE_ITEM % ("| " * (relpath.count(os.sep) + 1),
-                                   pc_str, newpath, name)
-
-def _skip_file(path, exclude):
-    if exclude:
-        return bool(re.search(exclude, path))
-
-def _graft(path, tree):
-    d = tree
-    
-    p = path
-    atoms = []
-    while True:
-        p, tail = os.path.split(p)
-        if not tail:
-            break
-        atoms.append(tail)
-    atoms.append(p)
-    if p != "/":
-        atoms.append("/")
-    
-    atoms.reverse()
-    for node in atoms:
-        if node:
-            d = d.setdefault(node, {})
-
-def get_tree(base, exclude):
-    """Return covered module names as a nested dict."""
-    tree = {}
-    coverage.get_ready()
-    runs = list(coverage.cexecuted.keys())
-    if runs:
-        for path in runs:
-            if not _skip_file(path, exclude) and not os.path.isdir(path):
-                _graft(path, tree)
-    return tree
-
-class CoverStats(object):
-    
-    def __init__(self, root=None):
-        if root is None:
-            # Guess initial depth. Files outside this path will not be
-            # reachable from the web interface.
-            import cherrypy
-            root = os.path.dirname(cherrypy.__file__)
-        self.root = root
-    
-    def index(self):
-        return TEMPLATE_FRAMESET % self.root.lower()
-    index.exposed = True
-    
-    def menu(self, base="/", pct="50", showpct="",
-             exclude=r'python\d\.\d|test|tut\d|tutorial'):
-        
-        # The coverage module uses all-lower-case names.
-        base = base.lower().rstrip(os.sep)
-        
-        yield TEMPLATE_MENU
-        yield TEMPLATE_FORM % locals()
-        
-        # Start by showing links for parent paths
-        yield "<div id='crumbs'>"
-        path = ""
-        atoms = base.split(os.sep)
-        atoms.pop()
-        for atom in atoms:
-            path += atom + os.sep
-            yield ("<a href='menu?base=%s&exclude=%s'>%s</a> %s"
-                   % (path, quote_plus(exclude), atom, os.sep))
-        yield "</div>"
-        
-        yield "<div id='tree'>"
-        
-        # Then display the tree
-        tree = get_tree(base, exclude)
-        if not tree:
-            yield "<p>No modules covered.</p>"
-        else:
-            for chunk in _show_branch(tree, base, "/", pct,
-                                      showpct=='checked', exclude):
-                yield chunk
-        
-        yield "</div>"
-        yield "</body></html>"
-    menu.exposed = True
-    
-    def annotated_file(self, filename, statements, excluded, missing):
-        source = open(filename, 'r')
-        buffer = []
-        for lineno, line in enumerate(source.readlines()):
-            lineno += 1
-            line = line.strip("\n\r")
-            empty_the_buffer = True
-            if lineno in excluded:
-                template = TEMPLATE_LOC_EXCLUDED
-            elif lineno in missing:
-                template = TEMPLATE_LOC_NOT_COVERED
-            elif lineno in statements:
-                template = TEMPLATE_LOC_COVERED
-            else:
-                empty_the_buffer = False
-                buffer.append((lineno, line))
-            if empty_the_buffer:
-                for lno, pastline in buffer:
-                    yield template % (lno, cgi.escape(pastline))
-                buffer = []
-                yield template % (lineno, cgi.escape(line))
-    
-    def report(self, name):
-        coverage.get_ready()
-        filename, statements, excluded, missing, _ = coverage.analysis2(name)
-        pc = _percent(statements, missing)
-        yield TEMPLATE_COVERAGE % dict(name=os.path.basename(name),
-                                       fullpath=name,
-                                       pc=pc)
-        yield '<table>\n'
-        for line in self.annotated_file(filename, statements, excluded,
-                                        missing):
-            yield line
-        yield '</table>'
-        yield '</body>'
-        yield '</html>'
-    report.exposed = True
-
-
-def serve(path=localFile, port=8080, root=None):
-    if coverage is None:
-        raise ImportError("The coverage module could not be imported.")
-    coverage.cache_default = path
-    
-    import cherrypy
-    cherrypy.config.update({'server.socket_port': int(port),
-                            'server.thread_pool': 10,
-                            'environment': "production",
-                            })
-    cherrypy.quickstart(CoverStats(root))
-
-if __name__ == "__main__":
-    serve(*tuple(sys.argv[1:]))
-
--- a/bundled/cherrypy/cherrypy/lib/cptools.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,580 +0,0 @@
-"""Functions for builtin CherryPy tools."""
-
-import logging
-try:
-    # Python 2.5+
-    from hashlib import md5
-except ImportError:
-    from md5 import new as md5
-import re
-
-try:
-    set
-except NameError:
-    from sets import Set as set
-
-import cherrypy
-from cherrypy.lib import httputil as _httputil
-
-
-#                     Conditional HTTP request support                     #
-
-def validate_etags(autotags=False, debug=False):
-    """Validate the current ETag against If-Match, If-None-Match headers.
-    
-    If autotags is True, an ETag response-header value will be provided
-    from an MD5 hash of the response body (unless some other code has
-    already provided an ETag header). If False (the default), the ETag
-    will not be automatic.
-    
-    WARNING: the autotags feature is not designed for URL's which allow
-    methods other than GET. For example, if a POST to the same URL returns
-    no content, the automatic ETag will be incorrect, breaking a fundamental
-    use for entity tags in a possibly destructive fashion. Likewise, if you
-    raise 304 Not Modified, the response body will be empty, the ETag hash
-    will be incorrect, and your application will break.
-    See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.24
-    """
-    response = cherrypy.serving.response
-    
-    # Guard against being run twice.
-    if hasattr(response, "ETag"):
-        return
-    
-    status, reason, msg = _httputil.valid_status(response.status)
-    
-    etag = response.headers.get('ETag')
-    
-    # Automatic ETag generation. See warning in docstring.
-    if etag:
-        if debug:
-            cherrypy.log('ETag already set: %s' % etag, 'TOOLS.ETAGS')
-    elif not autotags:
-        if debug:
-            cherrypy.log('Autotags off', 'TOOLS.ETAGS')
-    elif status != 200:
-        if debug:
-            cherrypy.log('Status not 200', 'TOOLS.ETAGS')
-    else:
-        etag = response.collapse_body()
-        etag = '"%s"' % md5(etag).hexdigest()
-        if debug:
-            cherrypy.log('Setting ETag: %s' % etag, 'TOOLS.ETAGS')
-        response.headers['ETag'] = etag
-    
-    response.ETag = etag
-    
-    # "If the request would, without the If-Match header field, result in
-    # anything other than a 2xx or 412 status, then the If-Match header
-    # MUST be ignored."
-    if debug:
-        cherrypy.log('Status: %s' % status, 'TOOLS.ETAGS')
-    if status >= 200 and status <= 299:
-        request = cherrypy.serving.request
-        
-        conditions = request.headers.elements('If-Match') or []
-        conditions = [str(x) for x in conditions]
-        if debug:
-            cherrypy.log('If-Match conditions: %s' % repr(conditions),
-                         'TOOLS.ETAGS')
-        if conditions and not (conditions == ["*"] or etag in conditions):
-            raise cherrypy.HTTPError(412, "If-Match failed: ETag %r did "
-                                     "not match %r" % (etag, conditions))
-        
-        conditions = request.headers.elements('If-None-Match') or []
-        conditions = [str(x) for x in conditions]
-        if debug:
-            cherrypy.log('If-None-Match conditions: %s' % repr(conditions),
-                         'TOOLS.ETAGS')
-        if conditions == ["*"] or etag in conditions:
-            if debug:
-                cherrypy.log('request.method: %s' % request.method, 'TOOLS.ETAGS')
-            if request.method in ("GET", "HEAD"):
-                raise cherrypy.HTTPRedirect([], 304)
-            else:
-                raise cherrypy.HTTPError(412, "If-None-Match failed: ETag %r "
-                                         "matched %r" % (etag, conditions))
-
-def validate_since():
-    """Validate the current Last-Modified against If-Modified-Since headers.
-    
-    If no code has set the Last-Modified response header, then no validation
-    will be performed.
-    """
-    response = cherrypy.serving.response
-    lastmod = response.headers.get('Last-Modified')
-    if lastmod:
-        status, reason, msg = _httputil.valid_status(response.status)
-        
-        request = cherrypy.serving.request
-        
-        since = request.headers.get('If-Unmodified-Since')
-        if since and since != lastmod:
-            if (status >= 200 and status <= 299) or status == 412:
-                raise cherrypy.HTTPError(412)
-        
-        since = request.headers.get('If-Modified-Since')
-        if since and since == lastmod:
-            if (status >= 200 and status <= 299) or status == 304:
-                if request.method in ("GET", "HEAD"):
-                    raise cherrypy.HTTPRedirect([], 304)
-                else:
-                    raise cherrypy.HTTPError(412)
-
-
-#                                Tool code                                #
-
-def proxy(base=None, local='X-Forwarded-Host', remote='X-Forwarded-For',
-          scheme='X-Forwarded-Proto', debug=False):
-    """Change the base URL (scheme://host[:port][/path]).
-    
-    For running a CP server behind Apache, lighttpd, or other HTTP server.
-    
-    If you want the new request.base to include path info (not just the host),
-    you must explicitly set base to the full base path, and ALSO set 'local'
-    to '', so that the X-Forwarded-Host request header (which never includes
-    path info) does not override it. Regardless, the value for 'base' MUST
-    NOT end in a slash.
-    
-    cherrypy.request.remote.ip (the IP address of the client) will be
-    rewritten if the header specified by the 'remote' arg is valid.
-    By default, 'remote' is set to 'X-Forwarded-For'. If you do not
-    want to rewrite remote.ip, set the 'remote' arg to an empty string.
-    """
-    
-    request = cherrypy.serving.request
-    
-    if scheme:
-        s = request.headers.get(scheme, None)
-        if debug:
-            cherrypy.log('Testing scheme %r:%r' % (scheme, s), 'TOOLS.PROXY')
-        if s == 'on' and 'ssl' in scheme.lower():
-            # This handles e.g. webfaction's 'X-Forwarded-Ssl: on' header
-            scheme = 'https'
-        else:
-            # This is for lighttpd/pound/Mongrel's 'X-Forwarded-Proto: https'
-            scheme = s
-    if not scheme:
-        scheme = request.base[:request.base.find("://")]
-    
-    if local:
-        lbase = request.headers.get(local, None)
-        if debug:
-            cherrypy.log('Testing local %r:%r' % (local, lbase), 'TOOLS.PROXY')
-        if lbase is not None:
-            base = lbase.split(',')[0]
-    if not base:
-        port = request.local.port
-        if port == 80:
-            base = '127.0.0.1'
-        else:
-            base = '127.0.0.1:%s' % port
-    
-    if base.find("://") == -1:
-        # add http:// or https:// if needed
-        base = scheme + "://" + base
-    
-    request.base = base
-    
-    if remote:
-        xff = request.headers.get(remote)
-        if debug:
-            cherrypy.log('Testing remote %r:%r' % (remote, xff), 'TOOLS.PROXY')
-        if xff:
-            if remote == 'X-Forwarded-For':
-                # See http://bob.pythonmac.org/archives/2005/09/23/apache-x-forwarded-for-caveat/
-                xff = xff.split(',')[-1].strip()
-            request.remote.ip = xff
-
-
-def ignore_headers(headers=('Range',), debug=False):
-    """Delete request headers whose field names are included in 'headers'.
-    
-    This is a useful tool for working behind certain HTTP servers;
-    for example, Apache duplicates the work that CP does for 'Range'
-    headers, and will doubly-truncate the response.
-    """
-    request = cherrypy.serving.request
-    for name in headers:
-        if name in request.headers:
-            if debug:
-                cherrypy.log('Ignoring request header %r' % name,
-                             'TOOLS.IGNORE_HEADERS')
-            del request.headers[name]
-
-
-def response_headers(headers=None, debug=False):
-    """Set headers on the response."""
-    if debug:
-        cherrypy.log('Setting response headers: %s' % repr(headers),
-                     'TOOLS.RESPONSE_HEADERS')
-    for name, value in (headers or []):
-        cherrypy.serving.response.headers[name] = value
-response_headers.failsafe = True
-
-
-def referer(pattern, accept=True, accept_missing=False, error=403,
-            message='Forbidden Referer header.', debug=False):
-    """Raise HTTPError if Referer header does/does not match the given pattern.
-    
-    pattern: a regular expression pattern to test against the Referer.
-    accept: if True, the Referer must match the pattern; if False,
-        the Referer must NOT match the pattern.
-    accept_missing: if True, permit requests with no Referer header.
-    error: the HTTP error code to return to the client on failure.
-    message: a string to include in the response body on failure.
-    """
-    try:
-        ref = cherrypy.serving.request.headers['Referer']
-        match = bool(re.match(pattern, ref))
-        if debug:
-            cherrypy.log('Referer %r matches %r' % (ref, pattern),
-                         'TOOLS.REFERER')
-        if accept == match:
-            return
-    except KeyError:
-        if debug:
-            cherrypy.log('No Referer header', 'TOOLS.REFERER')
-        if accept_missing:
-            return
-    
-    raise cherrypy.HTTPError(error, message)
-
-
-class SessionAuth(object):
-    """Assert that the user is logged in."""
-    
-    session_key = "username"
-    debug = False
-    
-    def check_username_and_password(self, username, password):
-        pass
-    
-    def anonymous(self):
-        """Provide a temporary user name for anonymous users."""
-        pass
-    
-    def on_login(self, username):
-        pass
-    
-    def on_logout(self, username):
-        pass
-    
-    def on_check(self, username):
-        pass
-    
-    def login_screen(self, from_page='..', username='', error_msg='', **kwargs):
-        return """<html><body>
-Message: %(error_msg)s
-<form method="post" action="do_login">
-    Login: <input type="text" name="username" value="%(username)s" size="10" /><br />
-    Password: <input type="password" name="password" size="10" /><br />
-    <input type="hidden" name="from_page" value="%(from_page)s" /><br />
-    <input type="submit" />
-</form>
-</body></html>""" % {'from_page': from_page, 'username': username,
-                     'error_msg': error_msg}
-    
-    def do_login(self, username, password, from_page='..', **kwargs):
-        """Login. May raise redirect, or return True if request handled."""
-        response = cherrypy.serving.response
-        error_msg = self.check_username_and_password(username, password)
-        if error_msg:
-            body = self.login_screen(from_page, username, error_msg)
-            response.body = body
-            if "Content-Length" in response.headers:
-                # Delete Content-Length header so finalize() recalcs it.
-                del response.headers["Content-Length"]
-            return True
-        else:
-            cherrypy.serving.request.login = username
-            cherrypy.session[self.session_key] = username
-            self.on_login(username)
-            raise cherrypy.HTTPRedirect(from_page or "/")
-    
-    def do_logout(self, from_page='..', **kwargs):
-        """Logout. May raise redirect, or return True if request handled."""
-        sess = cherrypy.session
-        username = sess.get(self.session_key)
-        sess[self.session_key] = None
-        if username:
-            cherrypy.serving.request.login = None
-            self.on_logout(username)
-        raise cherrypy.HTTPRedirect(from_page)
-    
-    def do_check(self):
-        """Assert username. May raise redirect, or return True if request handled."""
-        sess = cherrypy.session
-        request = cherrypy.serving.request
-        response = cherrypy.serving.response
-        
-        username = sess.get(self.session_key)
-        if not username:
-            sess[self.session_key] = username = self.anonymous()
-            if self.debug:
-                cherrypy.log('No session[username], trying anonymous', 'TOOLS.SESSAUTH')
-        if not username:
-            url = cherrypy.url(qs=request.query_string)
-            if self.debug:
-                cherrypy.log('No username, routing to login_screen with '
-                             'from_page %r' % url, 'TOOLS.SESSAUTH')
-            response.body = self.login_screen(url)
-            if "Content-Length" in response.headers:
-                # Delete Content-Length header so finalize() recalcs it.
-                del response.headers["Content-Length"]
-            return True
-        if self.debug:
-            cherrypy.log('Setting request.login to %r' % username, 'TOOLS.SESSAUTH')
-        request.login = username
-        self.on_check(username)
-    
-    def run(self):
-        request = cherrypy.serving.request
-        response = cherrypy.serving.response
-        
-        path = request.path_info
-        if path.endswith('login_screen'):
-            if self.debug:
-                cherrypy.log('routing %r to login_screen' % path, 'TOOLS.SESSAUTH')
-            return self.login_screen(**request.params)
-        elif path.endswith('do_login'):
-            if request.method != 'POST':
-                response.headers['Allow'] = "POST"
-                if self.debug:
-                    cherrypy.log('do_login requires POST', 'TOOLS.SESSAUTH')
-                raise cherrypy.HTTPError(405)
-            if self.debug:
-                cherrypy.log('routing %r to do_login' % path, 'TOOLS.SESSAUTH')
-            return self.do_login(**request.params)
-        elif path.endswith('do_logout'):
-            if request.method != 'POST':
-                response.headers['Allow'] = "POST"
-                raise cherrypy.HTTPError(405)
-            if self.debug:
-                cherrypy.log('routing %r to do_logout' % path, 'TOOLS.SESSAUTH')
-            return self.do_logout(**request.params)
-        else:
-            if self.debug:
-                cherrypy.log('No special path, running do_check', 'TOOLS.SESSAUTH')
-            return self.do_check()
-
-
-def session_auth(**kwargs):
-    sa = SessionAuth()
-    for k, v in kwargs.items():
-        setattr(sa, k, v)
-    return sa.run()
-session_auth.__doc__ = """Session authentication hook.
-
-Any attribute of the SessionAuth class may be overridden via a keyword arg
-to this function:
-
-""" + "\n".join(["%s: %s" % (k, type(getattr(SessionAuth, k)).__name__)
-                 for k in dir(SessionAuth) if not k.startswith("__")])
-
-
-def log_traceback(severity=logging.ERROR, debug=False):
-    """Write the last error's traceback to the cherrypy error log."""
-    cherrypy.log("", "HTTP", severity=severity, traceback=True)
-
-def log_request_headers(debug=False):
-    """Write request headers to the cherrypy error log."""
-    h = ["  %s: %s" % (k, v) for k, v in cherrypy.serving.request.header_list]
-    cherrypy.log('\nRequest Headers:\n' + '\n'.join(h), "HTTP")
-
-def log_hooks(debug=False):
-    """Write request.hooks to the cherrypy error log."""
-    request = cherrypy.serving.request
-    
-    msg = []
-    # Sort by the standard points if possible.
-    from cherrypy import _cprequest
-    points = _cprequest.hookpoints
-    for k in request.hooks.keys():
-        if k not in points:
-            points.append(k)
-    
-    for k in points:
-        msg.append("    %s:" % k)
-        v = request.hooks.get(k, [])
-        v.sort()
-        for h in v:
-            msg.append("        %r" % h)
-    cherrypy.log('\nRequest Hooks for ' + cherrypy.url() +
-                 ':\n' + '\n'.join(msg), "HTTP")
-
-def redirect(url='', internal=True, debug=False):
-    """Raise InternalRedirect or HTTPRedirect to the given url."""
-    if debug:
-        cherrypy.log('Redirecting %sto: %s' %
-                     ({True: 'internal ', False: ''}[internal], url),
-                     'TOOLS.REDIRECT')
-    if internal:
-        raise cherrypy.InternalRedirect(url)
-    else:
-        raise cherrypy.HTTPRedirect(url)
-
-def trailing_slash(missing=True, extra=False, status=None, debug=False):
-    """Redirect if path_info has (missing|extra) trailing slash."""
-    request = cherrypy.serving.request
-    pi = request.path_info
-    
-    if debug:
-        cherrypy.log('is_index: %r, missing: %r, extra: %r, path_info: %r' %
-                     (request.is_index, missing, extra, pi),
-                     'TOOLS.TRAILING_SLASH')
-    if request.is_index is True:
-        if missing:
-            if not pi.endswith('/'):
-                new_url = cherrypy.url(pi + '/', request.query_string)
-                raise cherrypy.HTTPRedirect(new_url, status=status or 301)
-    elif request.is_index is False:
-        if extra:
-            # If pi == '/', don't redirect to ''!
-            if pi.endswith('/') and pi != '/':
-                new_url = cherrypy.url(pi[:-1], request.query_string)
-                raise cherrypy.HTTPRedirect(new_url, status=status or 301)
-
-def flatten(debug=False):
-    """Wrap response.body in a generator that recursively iterates over body.
-    
-    This allows cherrypy.response.body to consist of 'nested generators';
-    that is, a set of generators that yield generators.
-    """
-    import types
-    def flattener(input):
-        numchunks = 0
-        for x in input:
-            if not isinstance(x, types.GeneratorType):
-                numchunks += 1
-                yield x
-            else:
-                for y in flattener(x):
-                    numchunks += 1
-                    yield y
-        if debug:
-            cherrypy.log('Flattened %d chunks' % numchunks, 'TOOLS.FLATTEN')
-    response = cherrypy.serving.response
-    response.body = flattener(response.body)
-
-
-def accept(media=None, debug=False):
-    """Return the client's preferred media-type (from the given Content-Types).
-    
-    If 'media' is None (the default), no test will be performed.
-    
-    If 'media' is provided, it should be the Content-Type value (as a string)
-    or values (as a list or tuple of strings) which the current resource
-    can emit. The client's acceptable media ranges (as declared in the
-    Accept request header) will be matched in order to these Content-Type
-    values; the first such string is returned. That is, the return value
-    will always be one of the strings provided in the 'media' arg (or None
-    if 'media' is None).
-    
-    If no match is found, then HTTPError 406 (Not Acceptable) is raised.
-    Note that most web browsers send */* as a (low-quality) acceptable
-    media range, which should match any Content-Type. In addition, "...if
-    no Accept header field is present, then it is assumed that the client
-    accepts all media types."
-    
-    Matching types are checked in order of client preference first,
-    and then in the order of the given 'media' values.
-    
-    Note that this function does not honor accept-params (other than "q").
-    """
-    if not media:
-        return
-    if isinstance(media, basestring):
-        media = [media]
-    request = cherrypy.serving.request
-    
-    # Parse the Accept request header, and try to match one
-    # of the requested media-ranges (in order of preference).
-    ranges = request.headers.elements('Accept')
-    if not ranges:
-        # Any media type is acceptable.
-        if debug:
-            cherrypy.log('No Accept header elements', 'TOOLS.ACCEPT')
-        return media[0]
-    else:
-        # Note that 'ranges' is sorted in order of preference
-        for element in ranges:
-            if element.qvalue > 0:
-                if element.value == "*/*":
-                    # Matches any type or subtype
-                    if debug:
-                        cherrypy.log('Match due to */*', 'TOOLS.ACCEPT')
-                    return media[0]
-                elif element.value.endswith("/*"):
-                    # Matches any subtype
-                    mtype = element.value[:-1]  # Keep the slash
-                    for m in media:
-                        if m.startswith(mtype):
-                            if debug:
-                                cherrypy.log('Match due to %s' % element.value,
-                                             'TOOLS.ACCEPT')
-                            return m
-                else:
-                    # Matches exact value
-                    if element.value in media:
-                        if debug:
-                            cherrypy.log('Match due to %s' % element.value,
-                                         'TOOLS.ACCEPT')
-                        return element.value
-    
-    # No suitable media-range found.
-    ah = request.headers.get('Accept')
-    if ah is None:
-        msg = "Your client did not send an Accept header."
-    else:
-        msg = "Your client sent this Accept header: %s." % ah
-    msg += (" But this resource only emits these media types: %s." %
-            ", ".join(media))
-    raise cherrypy.HTTPError(406, msg)
-
-
-class MonitoredHeaderMap(_httputil.HeaderMap):
-    
-    def __init__(self):
-        self.accessed_headers = set()
-    
-    def __getitem__(self, key):
-        self.accessed_headers.add(key)
-        return _httputil.HeaderMap.__getitem__(self, key)
-    
-    def __contains__(self, key):
-        self.accessed_headers.add(key)
-        return _httputil.HeaderMap.__contains__(self, key)
-    
-    def get(self, key, default=None):
-        self.accessed_headers.add(key)
-        return _httputil.HeaderMap.get(self, key, default=default)
-    
-    def has_key(self, key):
-        self.accessed_headers.add(key)
-        return _httputil.HeaderMap.has_key(self, key)
-
-
-def autovary(ignore=None, debug=False):
-    """Auto-populate the Vary response header based on request.header access."""
-    request = cherrypy.serving.request
-    
-    req_h = request.headers
-    request.headers = MonitoredHeaderMap()
-    request.headers.update(req_h)
-    if ignore is None:
-        ignore = set(['Content-Disposition', 'Content-Length', 'Content-Type'])
-    
-    def set_response_header():
-        resp_h = cherrypy.serving.response.headers
-        v = set([e.value for e in resp_h.elements('Vary')])
-        if debug:
-            cherrypy.log('Accessed headers: %s' % request.headers.accessed_headers,
-                         'TOOLS.AUTOVARY')
-        v = v.union(request.headers.accessed_headers)
-        v = v.difference(ignore)
-        v = list(v)
-        v.sort()
-        resp_h['Vary'] = ', '.join(v)
-    request.hooks.attach('before_finalize', set_response_header, 95)
-
--- a/bundled/cherrypy/cherrypy/lib/encoding.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,362 +0,0 @@
-try:
-    from cStringIO import StringIO
-except ImportError:
-    from StringIO import StringIO
-try:
-    set
-except NameError:
-    from sets import Set as set
-import struct
-import time
-import types
-
-import cherrypy
-from cherrypy.lib import file_generator
-from cherrypy.lib import set_vary_header
-
-
-def decode(encoding=None, default_encoding='utf-8'):
-    """Replace or extend the list of charsets used to decode a request entity.
-    
-    Either argument may be a single string or a list of strings.
-    
-    encoding: If not None, restricts the set of charsets attempted while decoding
-    a request entity to the given set (even if a different charset is given in
-    the Content-Type request header).
-    
-    default_encoding: Only in effect if the 'encoding' argument is not given.
-    If given, the set of charsets attempted while decoding a request entity is
-    *extended* with the given value(s).
-    """
-    body = cherrypy.request.body
-    if encoding is not None:
-        if not isinstance(encoding, list):
-            encoding = [encoding]
-        body.attempt_charsets = encoding
-    elif default_encoding:
-        if not isinstance(default_encoding, list):
-            default_encoding = [default_encoding]
-        body.attempt_charsets = body.attempt_charsets + default_encoding
-
-
-class ResponseEncoder:
-    
-    default_encoding = 'utf-8'
-    failmsg = "Response body could not be encoded with %r."
-    encoding = None
-    errors = 'strict'
-    text_only = True
-    add_charset = True
-    debug = False
-    
-    def __init__(self, **kwargs):
-        for k, v in kwargs.items():
-            setattr(self, k, v)
-        
-        self.attempted_charsets = set()
-        request = cherrypy.serving.request
-        if request.handler is not None:
-            # Replace request.handler with self
-            if self.debug:
-                cherrypy.log('Replacing request.handler', 'TOOLS.ENCODE')
-            self.oldhandler = request.handler
-            request.handler = self
-    
-    def encode_stream(self, encoding):
-        """Encode a streaming response body.
-        
-        Use a generator wrapper, and just pray it works as the stream is
-        being written out.
-        """
-        if encoding in self.attempted_charsets:
-            return False
-        self.attempted_charsets.add(encoding)
-        
-        def encoder(body):
-            for chunk in body:
-                if isinstance(chunk, unicode):
-                    chunk = chunk.encode(encoding, self.errors)
-                yield chunk
-        self.body = encoder(self.body)
-        return True
-    
-    def encode_string(self, encoding):
-        """Encode a buffered response body."""
-        if encoding in self.attempted_charsets:
-            return False
-        self.attempted_charsets.add(encoding)
-        
-        try:
-            body = []
-            for chunk in self.body:
-                if isinstance(chunk, unicode):
-                    chunk = chunk.encode(encoding, self.errors)
-                body.append(chunk)
-            self.body = body
-        except (LookupError, UnicodeError):
-            return False
-        else:
-            return True
-    
-    def find_acceptable_charset(self):
-        request = cherrypy.serving.request
-        response = cherrypy.serving.response
-        
-        if self.debug:
-            cherrypy.log('response.stream %r' % response.stream, 'TOOLS.ENCODE')
-        if response.stream:
-            encoder = self.encode_stream
-        else:
-            encoder = self.encode_string
-            if "Content-Length" in response.headers:
-                # Delete Content-Length header so finalize() recalcs it.
-                # Encoded strings may be of different lengths from their
-                # unicode equivalents, and even from each other. For example:
-                # >>> t = u"\u7007\u3040"
-                # >>> len(t)
-                # 2
-                # >>> len(t.encode("UTF-8"))
-                # 6
-                # >>> len(t.encode("utf7"))
-                # 8
-                del response.headers["Content-Length"]
-        
-        # Parse the Accept-Charset request header, and try to provide one
-        # of the requested charsets (in order of user preference).
-        encs = request.headers.elements('Accept-Charset')
-        charsets = [enc.value.lower() for enc in encs]
-        if self.debug:
-            cherrypy.log('charsets %s' % repr(charsets), 'TOOLS.ENCODE')
-        
-        if self.encoding is not None:
-            # If specified, force this encoding to be used, or fail.
-            encoding = self.encoding.lower()
-            if self.debug:
-                cherrypy.log('Specified encoding %r' % encoding, 'TOOLS.ENCODE')
-            if (not charsets) or "*" in charsets or encoding in charsets:
-                if self.debug:
-                    cherrypy.log('Attempting encoding %r' % encoding, 'TOOLS.ENCODE')
-                if encoder(encoding):
-                    return encoding
-        else:
-            if not encs:
-                if self.debug:
-                    cherrypy.log('Attempting default encoding %r' %
-                                 self.default_encoding, 'TOOLS.ENCODE')
-                # Any character-set is acceptable.
-                if encoder(self.default_encoding):
-                    return self.default_encoding
-                else:
-                    raise cherrypy.HTTPError(500, self.failmsg % self.default_encoding)
-            else:
-                if "*" not in charsets:
-                    # If no "*" is present in an Accept-Charset field, then all
-                    # character sets not explicitly mentioned get a quality
-                    # value of 0, except for ISO-8859-1, which gets a quality
-                    # value of 1 if not explicitly mentioned.
-                    iso = 'iso-8859-1'
-                    if iso not in charsets:
-                        if self.debug:
-                            cherrypy.log('Attempting ISO-8859-1 encoding',
-                                         'TOOLS.ENCODE')
-                        if encoder(iso):
-                            return iso
-                
-                for element in encs:
-                    if element.qvalue > 0:
-                        if element.value == "*":
-                            # Matches any charset. Try our default.
-                            if self.debug:
-                                cherrypy.log('Attempting default encoding due '
-                                             'to %r' % element, 'TOOLS.ENCODE')
-                            if encoder(self.default_encoding):
-                                return self.default_encoding
-                        else:
-                            encoding = element.value
-                            if self.debug:
-                                cherrypy.log('Attempting encoding %r (qvalue >'
-                                             '0)' % element, 'TOOLS.ENCODE')
-                            if encoder(encoding):
-                                return encoding
-        
-        # No suitable encoding found.
-        ac = request.headers.get('Accept-Charset')
-        if ac is None:
-            msg = "Your client did not send an Accept-Charset header."
-        else:
-            msg = "Your client sent this Accept-Charset header: %s." % ac
-        msg += " We tried these charsets: %s." % ", ".join(self.attempted_charsets)
-        raise cherrypy.HTTPError(406, msg)
-    
-    def __call__(self, *args, **kwargs):
-        response = cherrypy.serving.response
-        self.body = self.oldhandler(*args, **kwargs)
-        
-        if isinstance(self.body, basestring):
-            # strings get wrapped in a list because iterating over a single
-            # item list is much faster than iterating over every character
-            # in a long string.
-            if self.body:
-                self.body = [self.body]
-            else:
-                # [''] doesn't evaluate to False, so replace it with [].
-                self.body = []
-        elif isinstance(self.body, types.FileType):
-            self.body = file_generator(self.body)
-        elif self.body is None:
-            self.body = []
-        
-        ct = response.headers.elements("Content-Type")
-        if self.debug:
-            cherrypy.log('Content-Type: %r' % ct, 'TOOLS.ENCODE')
-        if ct:
-            if self.text_only:
-                ct = ct[0]
-                if ct.value.lower().startswith("text/"):
-                    if self.debug:
-                        cherrypy.log('Content-Type %r starts with "text/"' % ct,
-                                     'TOOLS.ENCODE')
-                    do_find = True
-                else:
-                    if self.debug:
-                        cherrypy.log('Not finding because Content-Type %r does '
-                                     'not start with "text/"' % ct,
-                                     'TOOLS.ENCODE')
-                    do_find = False
-            else:
-                if self.debug:
-                    cherrypy.log('Finding because not text_only', 'TOOLS.ENCODE')
-                do_find = True
-            
-            if do_find:
-                # Set "charset=..." param on response Content-Type header
-                ct.params['charset'] = self.find_acceptable_charset()
-                if self.add_charset:
-                    if self.debug:
-                        cherrypy.log('Setting Content-Type %r' % ct,
-                                     'TOOLS.ENCODE')
-                    response.headers["Content-Type"] = str(ct)
-        
-        return self.body
-
-# GZIP
-
-def compress(body, compress_level):
-    """Compress 'body' at the given compress_level."""
-    import zlib
-    
-    # See http://www.gzip.org/zlib/rfc-gzip.html
-    yield '\x1f\x8b'       # ID1 and ID2: gzip marker
-    yield '\x08'           # CM: compression method
-    yield '\x00'           # FLG: none set
-    # MTIME: 4 bytes
-    yield struct.pack("<L", int(time.time()) & 0xFFFFFFFFL)
-    yield '\x02'           # XFL: max compression, slowest algo
-    yield '\xff'           # OS: unknown
-    
-    crc = zlib.crc32("")
-    size = 0
-    zobj = zlib.compressobj(compress_level,
-                            zlib.DEFLATED, -zlib.MAX_WBITS,
-                            zlib.DEF_MEM_LEVEL, 0)
-    for line in body:
-        size += len(line)
-        crc = zlib.crc32(line, crc)
-        yield zobj.compress(line)
-    yield zobj.flush()
-    
-    # CRC32: 4 bytes
-    yield struct.pack("<L", crc & 0xFFFFFFFFL)
-    # ISIZE: 4 bytes
-    yield struct.pack("<L", size & 0xFFFFFFFFL)
-
-def decompress(body):
-    import gzip
-    
-    zbuf = StringIO()
-    zbuf.write(body)
-    zbuf.seek(0)
-    zfile = gzip.GzipFile(mode='rb', fileobj=zbuf)
-    data = zfile.read()
-    zfile.close()
-    return data
-
-
-def gzip(compress_level=5, mime_types=['text/html', 'text/plain'], debug=False):
-    """Try to gzip the response body if Content-Type in mime_types.
-    
-    cherrypy.response.headers['Content-Type'] must be set to one of the
-    values in the mime_types arg before calling this function.
-    
-    No compression is performed if any of the following hold:
-        * The client sends no Accept-Encoding request header
-        * No 'gzip' or 'x-gzip' is present in the Accept-Encoding header
-        * No 'gzip' or 'x-gzip' with a qvalue > 0 is present
-        * The 'identity' value is given with a qvalue > 0.
-    """
-    request = cherrypy.serving.request
-    response = cherrypy.serving.response
-    
-    set_vary_header(response, "Accept-Encoding")
-    
-    if not response.body:
-        # Response body is empty (might be a 304 for instance)
-        if debug:
-            cherrypy.log('No response body', context='TOOLS.GZIP')
-        return
-    
-    # If returning cached content (which should already have been gzipped),
-    # don't re-zip.
-    if getattr(request, "cached", False):
-        if debug:
-            cherrypy.log('Not gzipping cached response', context='TOOLS.GZIP')
-        return
-    
-    acceptable = request.headers.elements('Accept-Encoding')
-    if not acceptable:
-        # If no Accept-Encoding field is present in a request,
-        # the server MAY assume that the client will accept any
-        # content coding. In this case, if "identity" is one of
-        # the available content-codings, then the server SHOULD use
-        # the "identity" content-coding, unless it has additional
-        # information that a different content-coding is meaningful
-        # to the client.
-        if debug:
-            cherrypy.log('No Accept-Encoding', context='TOOLS.GZIP')
-        return
-    
-    ct = response.headers.get('Content-Type', '').split(';')[0]
-    for coding in acceptable:
-        if coding.value == 'identity' and coding.qvalue != 0:
-            if debug:
-                cherrypy.log('Non-zero identity qvalue: %r' % coding,
-                             context='TOOLS.GZIP')
-            return
-        if coding.value in ('gzip', 'x-gzip'):
-            if coding.qvalue == 0:
-                if debug:
-                    cherrypy.log('Zero gzip qvalue: %r' % coding,
-                                 context='TOOLS.GZIP')
-                return
-            
-            if ct not in mime_types:
-                if debug:
-                    cherrypy.log('Content-Type %r not in mime_types %r' %
-                                 (ct, mime_types), context='TOOLS.GZIP')
-                return
-            
-            if debug:
-                cherrypy.log('Gzipping', context='TOOLS.GZIP')
-            # Return a generator that compresses the page
-            response.headers['Content-Encoding'] = 'gzip'
-            response.body = compress(response.body, compress_level)
-            if "Content-Length" in response.headers:
-                # Delete Content-Length header so finalize() recalcs it.
-                del response.headers["Content-Length"]
-            
-            return
-    
-    if debug:
-        cherrypy.log('No acceptable encoding found.', context='GZIP')
-    cherrypy.HTTPError(406, "identity, gzip").set_response()
-
--- a/bundled/cherrypy/cherrypy/lib/http.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-import warnings
-warnings.warn('cherrypy.lib.http has been deprecated and will be removed '
-              'in CherryPy 3.3 use cherrypy.lib.httputil instead.',
-              DeprecationWarning)
-
-from cherrypy.lib.httputil import *
-
--- a/bundled/cherrypy/cherrypy/lib/httpauth.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,361 +0,0 @@
-"""
-httpauth modules defines functions to implement HTTP Digest Authentication (RFC 2617).
-This has full compliance with 'Digest' and 'Basic' authentication methods. In
-'Digest' it supports both MD5 and MD5-sess algorithms.
-
-Usage:
-
-    First use 'doAuth' to request the client authentication for a
-    certain resource. You should send an httplib.UNAUTHORIZED response to the
-    client so he knows he has to authenticate itself.
-    
-    Then use 'parseAuthorization' to retrieve the 'auth_map' used in
-    'checkResponse'.
-
-    To use 'checkResponse' you must have already verified the password associated
-    with the 'username' key in 'auth_map' dict. Then you use the 'checkResponse'
-    function to verify if the password matches the one sent by the client.
-
-SUPPORTED_ALGORITHM - list of supported 'Digest' algorithms
-SUPPORTED_QOP - list of supported 'Digest' 'qop'.
-"""
-__version__ = 1, 0, 1
-__author__ = "Tiago Cogumbreiro <cogumbreiro@users.sf.net>"
-__credits__ = """
-    Peter van Kampen for its recipe which implement most of Digest authentication:
-    http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/302378
-"""
-
-__license__ = """
-Copyright (c) 2005, Tiago Cogumbreiro <cogumbreiro@users.sf.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 of Sylvain Hellegouarch nor the names of his 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.
-"""
-
-__all__ = ("digestAuth", "basicAuth", "doAuth", "checkResponse",
-           "parseAuthorization", "SUPPORTED_ALGORITHM", "md5SessionKey",
-           "calculateNonce", "SUPPORTED_QOP")
-
-################################################################################
-try:
-    # Python 2.5+
-    from hashlib import md5
-except ImportError:
-    from md5 import new as md5
-import time
-import base64
-from urllib2 import parse_http_list, parse_keqv_list
-
-MD5 = "MD5"
-MD5_SESS = "MD5-sess"
-AUTH = "auth"
-AUTH_INT = "auth-int"
-
-SUPPORTED_ALGORITHM = (MD5, MD5_SESS)
-SUPPORTED_QOP = (AUTH, AUTH_INT)
-
-################################################################################
-# doAuth
-#
-DIGEST_AUTH_ENCODERS = {
-    MD5: lambda val: md5(val).hexdigest(),
-    MD5_SESS: lambda val: md5(val).hexdigest(),
-#    SHA: lambda val: sha.new (val).hexdigest (),
-}
-
-def calculateNonce (realm, algorithm = MD5):
-    """This is an auxaliary function that calculates 'nonce' value. It is used
-    to handle sessions."""
-
-    global SUPPORTED_ALGORITHM, DIGEST_AUTH_ENCODERS
-    assert algorithm in SUPPORTED_ALGORITHM
-
-    try:
-        encoder = DIGEST_AUTH_ENCODERS[algorithm]
-    except KeyError:
-        raise NotImplementedError ("The chosen algorithm (%s) does not have "\
-                                   "an implementation yet" % algorithm)
-
-    return encoder ("%d:%s" % (time.time(), realm))
-
-def digestAuth (realm, algorithm = MD5, nonce = None, qop = AUTH):
-    """Challenges the client for a Digest authentication."""
-    global SUPPORTED_ALGORITHM, DIGEST_AUTH_ENCODERS, SUPPORTED_QOP
-    assert algorithm in SUPPORTED_ALGORITHM
-    assert qop in SUPPORTED_QOP
-
-    if nonce is None:
-        nonce = calculateNonce (realm, algorithm)
-
-    return 'Digest realm="%s", nonce="%s", algorithm="%s", qop="%s"' % (
-        realm, nonce, algorithm, qop
-    )
-
-def basicAuth (realm):
-    """Challengenes the client for a Basic authentication."""
-    assert '"' not in realm, "Realms cannot contain the \" (quote) character."
-
-    return 'Basic realm="%s"' % realm
-
-def doAuth (realm):
-    """'doAuth' function returns the challenge string b giving priority over
-    Digest and fallback to Basic authentication when the browser doesn't
-    support the first one.
-    
-    This should be set in the HTTP header under the key 'WWW-Authenticate'."""
-
-    return digestAuth (realm) + " " + basicAuth (realm)
-
-
-################################################################################
-# Parse authorization parameters
-#
-def _parseDigestAuthorization (auth_params):
-    # Convert the auth params to a dict
-    items = parse_http_list(auth_params)
-    params = parse_keqv_list(items)
-
-    # Now validate the params
-
-    # Check for required parameters
-    required = ["username", "realm", "nonce", "uri", "response"]
-    for k in required:
-        if k not in params:
-            return None
-
-    # If qop is sent then cnonce and nc MUST be present
-    if "qop" in params and not ("cnonce" in params \
-                                      and "nc" in params):
-        return None
-
-    # If qop is not sent, neither cnonce nor nc can be present
-    if ("cnonce" in params or "nc" in params) and \
-       "qop" not in params:
-        return None
-
-    return params
-
-
-def _parseBasicAuthorization (auth_params):
-    username, password = base64.decodestring (auth_params).split (":", 1)
-    return {"username": username, "password": password}
-
-AUTH_SCHEMES = {
-    "basic": _parseBasicAuthorization,
-    "digest": _parseDigestAuthorization,
-}
-
-def parseAuthorization (credentials):
-    """parseAuthorization will convert the value of the 'Authorization' key in
-    the HTTP header to a map itself. If the parsing fails 'None' is returned.
-    """
-
-    global AUTH_SCHEMES
-
-    auth_scheme, auth_params  = credentials.split(" ", 1)
-    auth_scheme = auth_scheme.lower ()
-
-    parser = AUTH_SCHEMES[auth_scheme]
-    params = parser (auth_params)
-
-    if params is None:
-        return
-
-    assert "auth_scheme" not in params
-    params["auth_scheme"] = auth_scheme
-    return params
-
-
-################################################################################
-# Check provided response for a valid password
-#
-def md5SessionKey (params, password):
-    """
-    If the "algorithm" directive's value is "MD5-sess", then A1 
-    [the session key] is calculated only once - on the first request by the
-    client following receipt of a WWW-Authenticate challenge from the server.
-
-    This creates a 'session key' for the authentication of subsequent
-    requests and responses which is different for each "authentication
-    session", thus limiting the amount of material hashed with any one
-    key.
-
-    Because the server need only use the hash of the user
-    credentials in order to create the A1 value, this construction could
-    be used in conjunction with a third party authentication service so
-    that the web server would not need the actual password value.  The
-    specification of such a protocol is beyond the scope of this
-    specification.
-"""
-
-    keys = ("username", "realm", "nonce", "cnonce")
-    params_copy = {}
-    for key in keys:
-        params_copy[key] = params[key]
-
-    params_copy["algorithm"] = MD5_SESS
-    return _A1 (params_copy, password)
-
-def _A1(params, password):
-    algorithm = params.get ("algorithm", MD5)
-    H = DIGEST_AUTH_ENCODERS[algorithm]
-
-    if algorithm == MD5:
-        # If the "algorithm" directive's value is "MD5" or is
-        # unspecified, then A1 is:
-        # A1 = unq(username-value) ":" unq(realm-value) ":" passwd
-        return "%s:%s:%s" % (params["username"], params["realm"], password)
-
-    elif algorithm == MD5_SESS:
-
-        # This is A1 if qop is set
-        # A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd )
-        #         ":" unq(nonce-value) ":" unq(cnonce-value)
-        h_a1 = H ("%s:%s:%s" % (params["username"], params["realm"], password))
-        return "%s:%s:%s" % (h_a1, params["nonce"], params["cnonce"])
-
-
-def _A2(params, method, kwargs):
-    # If the "qop" directive's value is "auth" or is unspecified, then A2 is:
-    # A2 = Method ":" digest-uri-value
-
-    qop = params.get ("qop", "auth")
-    if qop == "auth":
-        return method + ":" + params["uri"]
-    elif qop == "auth-int":
-        # If the "qop" value is "auth-int", then A2 is:
-        # A2 = Method ":" digest-uri-value ":" H(entity-body)
-        entity_body = kwargs.get ("entity_body", "")
-        H = kwargs["H"]
-
-        return "%s:%s:%s" % (
-            method,
-            params["uri"],
-            H(entity_body)
-        )
-
-    else:
-        raise NotImplementedError ("The 'qop' method is unknown: %s" % qop)
-
-def _computeDigestResponse(auth_map, password, method = "GET", A1 = None,**kwargs):
-    """
-    Generates a response respecting the algorithm defined in RFC 2617
-    """
-    params = auth_map
-
-    algorithm = params.get ("algorithm", MD5)
-
-    H = DIGEST_AUTH_ENCODERS[algorithm]
-    KD = lambda secret, data: H(secret + ":" + data)
-
-    qop = params.get ("qop", None)
-
-    H_A2 = H(_A2(params, method, kwargs))
-
-    if algorithm == MD5_SESS and A1 is not None:
-        H_A1 = H(A1)
-    else:
-        H_A1 = H(_A1(params, password))
-
-    if qop in ("auth", "auth-int"):
-        # If the "qop" value is "auth" or "auth-int":
-        # request-digest  = <"> < KD ( H(A1),     unq(nonce-value)
-        #                              ":" nc-value
-        #                              ":" unq(cnonce-value)
-        #                              ":" unq(qop-value)
-        #                              ":" H(A2)
-        #                      ) <">
-        request = "%s:%s:%s:%s:%s" % (
-            params["nonce"],
-            params["nc"],
-            params["cnonce"],
-            params["qop"],
-            H_A2,
-        )
-    elif qop is None:
-        # If the "qop" directive is not present (this construction is
-        # for compatibility with RFC 2069):
-        # request-digest  =
-        #         <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
-        request = "%s:%s" % (params["nonce"], H_A2)
-
-    return KD(H_A1, request)
-
-def _checkDigestResponse(auth_map, password, method = "GET", A1 = None, **kwargs):
-    """This function is used to verify the response given by the client when
-    he tries to authenticate.
-    Optional arguments:
-     entity_body - when 'qop' is set to 'auth-int' you MUST provide the
-                   raw data you are going to send to the client (usually the
-                   HTML page.
-     request_uri - the uri from the request line compared with the 'uri'
-                   directive of the authorization map. They must represent
-                   the same resource (unused at this time).
-    """
-
-    if auth_map['realm'] != kwargs.get('realm', None):
-        return False
-
-    response =  _computeDigestResponse(auth_map, password, method, A1,**kwargs)
-
-    return response == auth_map["response"]
-
-def _checkBasicResponse (auth_map, password, method='GET', encrypt=None, **kwargs):
-    # Note that the Basic response doesn't provide the realm value so we cannot
-    # test it
-    try:
-        return encrypt(auth_map["password"], auth_map["username"]) == password
-    except TypeError:
-        return encrypt(auth_map["password"]) == password
-
-AUTH_RESPONSES = {
-    "basic": _checkBasicResponse,
-    "digest": _checkDigestResponse,
-}
-
-def checkResponse (auth_map, password, method = "GET", encrypt=None, **kwargs):
-    """'checkResponse' compares the auth_map with the password and optionally
-    other arguments that each implementation might need.
-    
-    If the response is of type 'Basic' then the function has the following
-    signature:
-    
-    checkBasicResponse (auth_map, password) -> bool
-    
-    If the response is of type 'Digest' then the function has the following
-    signature:
-    
-    checkDigestResponse (auth_map, password, method = 'GET', A1 = None) -> bool
-    
-    The 'A1' argument is only used in MD5_SESS algorithm based responses.
-    Check md5SessionKey() for more info.
-    """
-    global AUTH_RESPONSES
-    checker = AUTH_RESPONSES[auth_map["auth_scheme"]]
-    return checker (auth_map, password, method=method, encrypt=encrypt, **kwargs)
- 
-
-
-
--- a/bundled/cherrypy/cherrypy/lib/httputil.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,446 +0,0 @@
-"""HTTP library functions."""
-
-# This module contains functions for building an HTTP application
-# framework: any one, not just one whose name starts with "Ch". ;) If you
-# reference any modules from some popular framework inside *this* module,
-# FuManChu will personally hang you up by your thumbs and submit you
-# to a public caning.
-
-from binascii import b2a_base64
-from BaseHTTPServer import BaseHTTPRequestHandler
-response_codes = BaseHTTPRequestHandler.responses.copy()
-
-# From http://www.cherrypy.org/ticket/361
-response_codes[500] = ('Internal Server Error',
-                      'The server encountered an unexpected condition '
-                      'which prevented it from fulfilling the request.')
-response_codes[503] = ('Service Unavailable',
-                      'The server is currently unable to handle the '
-                      'request due to a temporary overloading or '
-                      'maintenance of the server.')
-
-import re
-import urllib
-
-from rfc822 import formatdate as HTTPDate
-
-
-def urljoin(*atoms):
-    """Return the given path *atoms, joined into a single URL.
-    
-    This will correctly join a SCRIPT_NAME and PATH_INFO into the
-    original URL, even if either atom is blank.
-    """
-    url = "/".join([x for x in atoms if x])
-    while "//" in url:
-        url = url.replace("//", "/")
-    # Special-case the final url of "", and return "/" instead.
-    return url or "/"
-
-def protocol_from_http(protocol_str):
-    """Return a protocol tuple from the given 'HTTP/x.y' string."""
-    return int(protocol_str[5]), int(protocol_str[7])
-
-def get_ranges(headervalue, content_length):
-    """Return a list of (start, stop) indices from a Range header, or None.
-    
-    Each (start, stop) tuple will be composed of two ints, which are suitable
-    for use in a slicing operation. That is, the header "Range: bytes=3-6",
-    if applied against a Python string, is requesting resource[3:7]. This
-    function will return the list [(3, 7)].
-    
-    If this function returns an empty list, you should return HTTP 416.
-    """
-    
-    if not headervalue:
-        return None
-    
-    result = []
-    bytesunit, byteranges = headervalue.split("=", 1)
-    for brange in byteranges.split(","):
-        start, stop = [x.strip() for x in brange.split("-", 1)]
-        if start:
-            if not stop:
-                stop = content_length - 1
-            start, stop = int(start), int(stop)
-            if start >= content_length:
-                # From rfc 2616 sec 14.16:
-                # "If the server receives a request (other than one
-                # including an If-Range request-header field) with an
-                # unsatisfiable Range request-header field (that is,
-                # all of whose byte-range-spec values have a first-byte-pos
-                # value greater than the current length of the selected
-                # resource), it SHOULD return a response code of 416
-                # (Requested range not satisfiable)."
-                continue
-            if stop < start:
-                # From rfc 2616 sec 14.16:
-                # "If the server ignores a byte-range-spec because it
-                # is syntactically invalid, the server SHOULD treat
-                # the request as if the invalid Range header field
-                # did not exist. (Normally, this means return a 200
-                # response containing the full entity)."
-                return None
-            result.append((start, stop + 1))
-        else:
-            if not stop:
-                # See rfc quote above.
-                return None
-            # Negative subscript (last N bytes)
-            result.append((content_length - int(stop), content_length))
-    
-    return result
-
-
-class HeaderElement(object):
-    """An element (with parameters) from an HTTP header's element list."""
-    
-    def __init__(self, value, params=None):
-        self.value = value
-        if params is None:
-            params = {}
-        self.params = params
-    
-    def __cmp__(self, other):
-        return cmp(self.value, other.value)
-    
-    def __unicode__(self):
-        p = [";%s=%s" % (k, v) for k, v in self.params.iteritems()]
-        return u"%s%s" % (self.value, "".join(p))
-    
-    def __str__(self):
-        return str(self.__unicode__())
-    
-    def parse(elementstr):
-        """Transform 'token;key=val' to ('token', {'key': 'val'})."""
-        # Split the element into a value and parameters. The 'value' may
-        # be of the form, "token=token", but we don't split that here.
-        atoms = [x.strip() for x in elementstr.split(";") if x.strip()]
-        if not atoms:
-            initial_value = ''
-        else:
-            initial_value = atoms.pop(0).strip()
-        params = {}
-        for atom in atoms:
-            atom = [x.strip() for x in atom.split("=", 1) if x.strip()]
-            key = atom.pop(0)
-            if atom:
-                val = atom[0]
-            else:
-                val = ""
-            params[key] = val
-        return initial_value, params
-    parse = staticmethod(parse)
-    
-    def from_str(cls, elementstr):
-        """Construct an instance from a string of the form 'token;key=val'."""
-        ival, params = cls.parse(elementstr)
-        return cls(ival, params)
-    from_str = classmethod(from_str)
-
-
-q_separator = re.compile(r'; *q *=')
-
-class AcceptElement(HeaderElement):
-    """An element (with parameters) from an Accept* header's element list.
-    
-    AcceptElement objects are comparable; the more-preferred object will be
-    "less than" the less-preferred object. They are also therefore sortable;
-    if you sort a list of AcceptElement objects, they will be listed in
-    priority order; the most preferred value will be first. Yes, it should
-    have been the other way around, but it's too late to fix now.
-    """
-    
-    def from_str(cls, elementstr):
-        qvalue = None
-        # The first "q" parameter (if any) separates the initial
-        # media-range parameter(s) (if any) from the accept-params.
-        atoms = q_separator.split(elementstr, 1)
-        media_range = atoms.pop(0).strip()
-        if atoms:
-            # The qvalue for an Accept header can have extensions. The other
-            # headers cannot, but it's easier to parse them as if they did.
-            qvalue = HeaderElement.from_str(atoms[0].strip())
-        
-        media_type, params = cls.parse(media_range)
-        if qvalue is not None:
-            params["q"] = qvalue
-        return cls(media_type, params)
-    from_str = classmethod(from_str)
-    
-    def qvalue(self):
-        val = self.params.get("q", "1")
-        if isinstance(val, HeaderElement):
-            val = val.value
-        return float(val)
-    qvalue = property(qvalue, doc="The qvalue, or priority, of this value.")
-    
-    def __cmp__(self, other):
-        diff = cmp(self.qvalue, other.qvalue)
-        if diff == 0:
-            diff = cmp(str(self), str(other))
-        return diff
-
-
-def header_elements(fieldname, fieldvalue):
-    """Return a sorted HeaderElement list from a comma-separated header str."""
-    if not fieldvalue:
-        return []
-    
-    result = []
-    for element in fieldvalue.split(","):
-        if fieldname.startswith("Accept") or fieldname == 'TE':
-            hv = AcceptElement.from_str(element)
-        else:
-            hv = HeaderElement.from_str(element)
-        result.append(hv)
-    result.sort()
-    result.reverse()
-    return result
-
-def decode_TEXT(value):
-    """Decode RFC-2047 TEXT (e.g. "=?utf-8?q?f=C3=BCr?=" -> u"f\xfcr")."""
-    from email.Header import decode_header
-    atoms = decode_header(value)
-    decodedvalue = ""
-    for atom, charset in atoms:
-        if charset is not None:
-            atom = atom.decode(charset)
-        decodedvalue += atom
-    return decodedvalue
-
-def valid_status(status):
-    """Return legal HTTP status Code, Reason-phrase and Message.
-    
-    The status arg must be an int, or a str that begins with an int.
-    
-    If status is an int, or a str and no reason-phrase is supplied,
-    a default reason-phrase will be provided.
-    """
-    
-    if not status:
-        status = 200
-    
-    status = str(status)
-    parts = status.split(" ", 1)
-    if len(parts) == 1:
-        # No reason supplied.
-        code, = parts
-        reason = None
-    else:
-        code, reason = parts
-        reason = reason.strip()
-    
-    try:
-        code = int(code)
-    except ValueError:
-        raise ValueError("Illegal response status from server "
-                         "(%s is non-numeric)." % repr(code))
-    
-    if code < 100 or code > 599:
-        raise ValueError("Illegal response status from server "
-                         "(%s is out of range)." % repr(code))
-    
-    if code not in response_codes:
-        # code is unknown but not illegal
-        default_reason, message = "", ""
-    else:
-        default_reason, message = response_codes[code]
-    
-    if reason is None:
-        reason = default_reason
-    
-    return code, reason, message
-
-
-def _parse_qs(qs, keep_blank_values=0, strict_parsing=0, encoding='utf-8'):
-    """Parse a query given as a string argument.
-
-    Arguments:
-
-    qs: URL-encoded query string to be parsed
-
-    keep_blank_values: flag indicating whether blank values in
-        URL encoded queries should be treated as blank strings.  A
-        true value indicates that blanks should be retained as blank
-        strings.  The default false value indicates that blank values
-        are to be ignored and treated as if they were  not included.
-
-    strict_parsing: flag indicating what to do with parsing errors. If
-        false (the default), errors are silently ignored. If true,
-        errors raise a ValueError exception.
-
-    Returns a dict, as G-d intended.
-    """
-    pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')]
-    d = {}
-    for name_value in pairs:
-        if not name_value and not strict_parsing:
-            continue
-        nv = name_value.split('=', 1)
-        if len(nv) != 2:
-            if strict_parsing:
-                raise ValueError("bad query field: %r" % (name_value,))
-            # Handle case of a control-name with no equal sign
-            if keep_blank_values:
-                nv.append('')
-            else:
-                continue
-        if len(nv[1]) or keep_blank_values:
-            name = urllib.unquote(nv[0].replace('+', ' '))
-            name = name.decode(encoding, 'strict')
-            value = urllib.unquote(nv[1].replace('+', ' '))
-            value = value.decode(encoding, 'strict')
-            if name in d:
-                if not isinstance(d[name], list):
-                    d[name] = [d[name]]
-                d[name].append(value)
-            else:
-                d[name] = value
-    return d
-
-
-image_map_pattern = re.compile(r"[0-9]+,[0-9]+")
-
-def parse_query_string(query_string, keep_blank_values=True, encoding='utf-8'):
-    """Build a params dictionary from a query_string.
-    
-    Duplicate key/value pairs in the provided query_string will be
-    returned as {'key': [val1, val2, ...]}. Single key/values will
-    be returned as strings: {'key': 'value'}.
-    """
-    if image_map_pattern.match(query_string):
-        # Server-side image map. Map the coords to 'x' and 'y'
-        # (like CGI::Request does).
-        pm = query_string.split(",")
-        pm = {'x': int(pm[0]), 'y': int(pm[1])}
-    else:
-        pm = _parse_qs(query_string, keep_blank_values, encoding=encoding)
-    return pm
-
-
-class CaseInsensitiveDict(dict):
-    """A case-insensitive dict subclass.
-    
-    Each key is changed on entry to str(key).title().
-    """
-    
-    def __getitem__(self, key):
-        return dict.__getitem__(self, str(key).title())
-    
-    def __setitem__(self, key, value):
-        dict.__setitem__(self, str(key).title(), value)
-    
-    def __delitem__(self, key):
-        dict.__delitem__(self, str(key).title())
-    
-    def __contains__(self, key):
-        return dict.__contains__(self, str(key).title())
-    
-    def get(self, key, default=None):
-        return dict.get(self, str(key).title(), default)
-    
-    def has_key(self, key):
-        return dict.has_key(self, str(key).title())
-    
-    def update(self, E):
-        for k in E.keys():
-            self[str(k).title()] = E[k]
-    
-    def fromkeys(cls, seq, value=None):
-        newdict = cls()
-        for k in seq:
-            newdict[str(k).title()] = value
-        return newdict
-    fromkeys = classmethod(fromkeys)
-    
-    def setdefault(self, key, x=None):
-        key = str(key).title()
-        try:
-            return self[key]
-        except KeyError:
-            self[key] = x
-            return x
-    
-    def pop(self, key, default):
-        return dict.pop(self, str(key).title(), default)
-
-
-class HeaderMap(CaseInsensitiveDict):
-    """A dict subclass for HTTP request and response headers.
-    
-    Each key is changed on entry to str(key).title(). This allows headers
-    to be case-insensitive and avoid duplicates.
-    
-    Values are header values (decoded according to RFC 2047 if necessary).
-    """
-    
-    protocol=(1, 1)
-    
-    def elements(self, key):
-        """Return a sorted list of HeaderElements for the given header."""
-        key = str(key).title()
-        value = self.get(key)
-        return header_elements(key, value)
-    
-    def values(self, key):
-        """Return a sorted list of HeaderElement.value for the given header."""
-        return [e.value for e in self.elements(key)]
-    
-    def output(self):
-        """Transform self into a list of (name, value) tuples."""
-        header_list = []
-        for k, v in self.items():
-            if isinstance(k, unicode):
-                k = k.encode("ISO-8859-1")
-            
-            if not isinstance(v, basestring):
-                v = str(v)
-            
-            if isinstance(v, unicode):
-                v = self.encode(v)
-            header_list.append((k, v))
-        return header_list
-    
-    def encode(self, v):
-        """Return the given header value, encoded for HTTP output."""
-        # HTTP/1.0 says, "Words of *TEXT may contain octets 
-        # from character sets other than US-ASCII." and 
-        # "Recipients of header field TEXT containing octets 
-        # outside the US-ASCII character set may assume that 
-        # they represent ISO-8859-1 characters." 
-        try:
-            v = v.encode("ISO-8859-1")
-        except UnicodeEncodeError:
-            if self.protocol == (1, 1):
-                # Encode RFC-2047 TEXT 
-                # (e.g. u"\u8200" -> "=?utf-8?b?6IiA?="). 
-                # We do our own here instead of using the email module
-                # because we never want to fold lines--folding has
-                # been deprecated by the HTTP working group.
-                v = b2a_base64(v.encode('utf-8'))
-                v = ('=?utf-8?b?' + v.strip('\n') + '?=')
-            else:
-                raise
-        return v
-
-class Host(object):
-    """An internet address.
-    
-    name should be the client's host name. If not available (because no DNS
-        lookup is performed), the IP address should be used instead.
-    """
-    
-    ip = "0.0.0.0"
-    port = 80
-    name = "unknown.tld"
-    
-    def __init__(self, ip, port, name=None):
-        self.ip = ip
-        self.port = port
-        if name is None:
-            name = ip
-        self.name = name
-    
-    def __repr__(self):
-        return "httputil.Host(%r, %r, %r)" % (self.ip, self.port, self.name)
--- a/bundled/cherrypy/cherrypy/lib/jsontools.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-import sys
-import cherrypy
-
-if sys.version_info >= (2, 6):
-    # Python 2.6: simplejson is part of the standard library
-    import json
-else:
-    try:
-        import simplejson as json
-    except ImportError:
-        json = None
-
-if json is None:
-    def json_decode(s):
-        raise ValueError('No JSON library is available')
-    def json_encode(s):
-        raise ValueError('No JSON library is available')
-else:
-    json_decode = json.JSONDecoder().decode
-    json_encode = json.JSONEncoder().iterencode
-
-def json_in(force=True, debug=False):
-    request = cherrypy.serving.request
-    def json_processor(entity):
-        """Read application/json data into request.json."""
-        if not entity.headers.get(u"Content-Length", u""):
-            raise cherrypy.HTTPError(411)
-        
-        body = entity.fp.read()
-        try:
-            request.json = json_decode(body)
-        except ValueError:
-            raise cherrypy.HTTPError(400, 'Invalid JSON document')
-    if force:
-        request.body.processors.clear()
-        request.body.default_proc = cherrypy.HTTPError(
-            415, 'Expected an application/json content type')
-    request.body.processors[u'application/json'] = json_processor
-
-def json_out(debug=False):
-    request = cherrypy.serving.request
-    response = cherrypy.serving.response
-    
-    real_handler = request.handler
-    def json_handler(*args, **kwargs):
-        response.headers['Content-Type'] = 'application/json'
-        value = real_handler(*args, **kwargs)
-        return json_encode(value)
-    request.handler = json_handler
-
--- a/bundled/cherrypy/cherrypy/lib/profiler.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,205 +0,0 @@
-"""Profiler tools for CherryPy.
-
-CherryPy users
-==============
-
-You can profile any of your pages as follows:
-
-    from cherrypy.lib import profiler
-    
-    class Root:
-        p = profile.Profiler("/path/to/profile/dir")
-        
-        def index(self):
-            self.p.run(self._index)
-        index.exposed = True
-        
-        def _index(self):
-            return "Hello, world!"
-    
-    cherrypy.tree.mount(Root())
-
-
-You can also turn on profiling for all requests
-using the make_app function as WSGI middleware.
-
-
-CherryPy developers
-===================
-
-This module can be used whenever you make changes to CherryPy,
-to get a quick sanity-check on overall CP performance. Use the
-"--profile" flag when running the test suite. Then, use the serve()
-function to browse the results in a web browser. If you run this
-module from the command line, it will call serve() for you.
-
-"""
-
-
-# Make profiler output more readable by adding __init__ modules' parents.
-def new_func_strip_path(func_name):
-    filename, line, name = func_name
-    if filename.endswith("__init__.py"):
-        return os.path.basename(filename[:-12]) + filename[-12:], line, name
-    return os.path.basename(filename), line, name
-
-try:
-    import profile
-    import pstats
-    pstats.func_strip_path = new_func_strip_path
-except ImportError:
-    profile = None
-    pstats = None
-
-import os, os.path
-import sys
-import warnings
-
-try:
-    from cStringIO import StringIO
-except ImportError:
-    from StringIO import StringIO
-
-_count = 0
-
-class Profiler(object):
-    
-    def __init__(self, path=None):
-        if not path:
-            path = os.path.join(os.path.dirname(__file__), "profile")
-        self.path = path
-        if not os.path.exists(path):
-            os.makedirs(path)
-    
-    def run(self, func, *args, **params):
-        """Dump profile data into self.path."""
-        global _count
-        c = _count = _count + 1
-        path = os.path.join(self.path, "cp_%04d.prof" % c)
-        prof = profile.Profile()
-        result = prof.runcall(func, *args, **params)
-        prof.dump_stats(path)
-        return result
-    
-    def statfiles(self):
-        """statfiles() -> list of available profiles."""
-        return [f for f in os.listdir(self.path)
-                if f.startswith("cp_") and f.endswith(".prof")]
-    
-    def stats(self, filename, sortby='cumulative'):
-        """stats(index) -> output of print_stats() for the given profile."""
-        sio = StringIO()
-        if sys.version_info >= (2, 5):
-            s = pstats.Stats(os.path.join(self.path, filename), stream=sio)
-            s.strip_dirs()
-            s.sort_stats(sortby)
-            s.print_stats()
-        else:
-            # pstats.Stats before Python 2.5 didn't take a 'stream' arg,
-            # but just printed to stdout. So re-route stdout.
-            s = pstats.Stats(os.path.join(self.path, filename))
-            s.strip_dirs()
-            s.sort_stats(sortby)
-            oldout = sys.stdout
-            try:
-                sys.stdout = sio
-                s.print_stats()
-            finally:
-                sys.stdout = oldout
-        response = sio.getvalue()
-        sio.close()
-        return response
-    
-    def index(self):
-        return """<html>
-        <head><title>CherryPy profile data</title></head>
-        <frameset cols='200, 1*'>
-            <frame src='menu' />
-            <frame name='main' src='' />
-        </frameset>
-        </html>
-        """
-    index.exposed = True
-    
-    def menu(self):
-        yield "<h2>Profiling runs</h2>"
-        yield "<p>Click on one of the runs below to see profiling data.</p>"
-        runs = self.statfiles()
-        runs.sort()
-        for i in runs:
-            yield "<a href='report?filename=%s' target='main'>%s</a><br />" % (i, i)
-    menu.exposed = True
-    
-    def report(self, filename):
-        import cherrypy
-        cherrypy.response.headers['Content-Type'] = 'text/plain'
-        return self.stats(filename)
-    report.exposed = True
-
-
-class ProfileAggregator(Profiler):
-    
-    def __init__(self, path=None):
-        Profiler.__init__(self, path)
-        global _count
-        self.count = _count = _count + 1
-        self.profiler = profile.Profile()
-    
-    def run(self, func, *args):
-        path = os.path.join(self.path, "cp_%04d.prof" % self.count)
-        result = self.profiler.runcall(func, *args)
-        self.profiler.dump_stats(path)
-        return result
-
-
-class make_app:
-    def __init__(self, nextapp, path=None, aggregate=False):
-        """Make a WSGI middleware app which wraps 'nextapp' with profiling.
-        
-        nextapp: the WSGI application to wrap, usually an instance of
-            cherrypy.Application.
-        path: where to dump the profiling output.
-        aggregate: if True, profile data for all HTTP requests will go in
-            a single file. If False (the default), each HTTP request will
-            dump its profile data into a separate file.
-        """
-        if profile is None or pstats is None:
-            msg = ("Your installation of Python does not have a profile module. "
-                   "If you're on Debian, try `sudo apt-get install python-profiler`. "
-                   "See http://www.cherrypy.org/wiki/ProfilingOnDebian for details.")
-            warnings.warn(msg)
-        
-        self.nextapp = nextapp
-        self.aggregate = aggregate
-        if aggregate:
-            self.profiler = ProfileAggregator(path)
-        else:
-            self.profiler = Profiler(path)
-    
-    def __call__(self, environ, start_response):
-        def gather():
-            result = []
-            for line in self.nextapp(environ, start_response):
-                result.append(line)
-            return result
-        return self.profiler.run(gather)
-
-
-def serve(path=None, port=8080):
-    if profile is None or pstats is None:
-        msg = ("Your installation of Python does not have a profile module. "
-               "If you're on Debian, try `sudo apt-get install python-profiler`. "
-               "See http://www.cherrypy.org/wiki/ProfilingOnDebian for details.")
-        warnings.warn(msg)
-    
-    import cherrypy
-    cherrypy.config.update({'server.socket_port': int(port),
-                            'server.thread_pool': 10,
-                            'environment': "production",
-                            })
-    cherrypy.quickstart(Profiler(path))
-
-
-if __name__ == "__main__":
-    serve(*tuple(sys.argv[1:]))
-
--- a/bundled/cherrypy/cherrypy/lib/reprconf.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,345 +0,0 @@
-"""Generic configuration system using unrepr.
-
-Configuration data may be supplied as a Python dictionary, as a filename,
-or as an open file object. When you supply a filename or file, Python's
-builtin ConfigParser is used (with some extensions).
-
-Namespaces
-----------
-
-Configuration keys are separated into namespaces by the first "." in the key.
-
-The only key that cannot exist in a namespace is the "environment" entry.
-This special entry 'imports' other config entries from a template stored in
-the Config.environments dict.
-
-You can define your own namespaces to be called when new config is merged
-by adding a named handler to Config.namespaces. The name can be any string,
-and the handler must be either a callable or a context manager.
-"""
-
-from ConfigParser import ConfigParser
-try:
-    set
-except NameError:
-    from sets import Set as set
-import sys
-
-def as_dict(config):
-    """Return a dict from 'config' whether it is a dict, file, or filename."""
-    if isinstance(config, basestring):
-        config = Parser().dict_from_file(config)
-    elif hasattr(config, 'read'):
-        config = Parser().dict_from_file(config)
-    return config
-
-
-class NamespaceSet(dict):
-    """A dict of config namespace names and handlers.
-    
-    Each config entry should begin with a namespace name; the corresponding
-    namespace handler will be called once for each config entry in that
-    namespace, and will be passed two arguments: the config key (with the
-    namespace removed) and the config value.
-    
-    Namespace handlers may be any Python callable; they may also be
-    Python 2.5-style 'context managers', in which case their __enter__
-    method should return a callable to be used as the handler.
-    See cherrypy.tools (the Toolbox class) for an example.
-    """
-    
-    def __call__(self, config):
-        """Iterate through config and pass it to each namespace handler.
-        
-        'config' should be a flat dict, where keys use dots to separate
-        namespaces, and values are arbitrary.
-        
-        The first name in each config key is used to look up the corresponding
-        namespace handler. For example, a config entry of {'tools.gzip.on': v}
-        will call the 'tools' namespace handler with the args: ('gzip.on', v)
-        """
-        # Separate the given config into namespaces
-        ns_confs = {}
-        for k in config:
-            if "." in k:
-                ns, name = k.split(".", 1)
-                bucket = ns_confs.setdefault(ns, {})
-                bucket[name] = config[k]
-        
-        # I chose __enter__ and __exit__ so someday this could be
-        # rewritten using Python 2.5's 'with' statement:
-        # for ns, handler in self.iteritems():
-        #     with handler as callable:
-        #         for k, v in ns_confs.get(ns, {}).iteritems():
-        #             callable(k, v)
-        for ns, handler in self.items():
-            exit = getattr(handler, "__exit__", None)
-            if exit:
-                callable = handler.__enter__()
-                no_exc = True
-                try:
-                    try:
-                        for k, v in ns_confs.get(ns, {}).items():
-                            callable(k, v)
-                    except:
-                        # The exceptional case is handled here
-                        no_exc = False
-                        if exit is None:
-                            raise
-                        if not exit(*sys.exc_info()):
-                            raise
-                        # The exception is swallowed if exit() returns true
-                finally:
-                    # The normal and non-local-goto cases are handled here
-                    if no_exc and exit:
-                        exit(None, None, None)
-            else:
-                for k, v in ns_confs.get(ns, {}).items():
-                    handler(k, v)
-    
-    def __repr__(self):
-        return "%s.%s(%s)" % (self.__module__, self.__class__.__name__,
-                              dict.__repr__(self))
-    
-    def __copy__(self):
-        newobj = self.__class__()
-        newobj.update(self)
-        return newobj
-    copy = __copy__
-
-
-class Config(dict):
-    """A dict-like set of configuration data, with defaults and namespaces.
-    
-    May take a file, filename, or dict.
-    """
-    
-    defaults = {}
-    environments = {}
-    namespaces = NamespaceSet()
-    
-    def __init__(self, file=None, **kwargs):
-        self.reset()
-        if file is not None:
-            self.update(file)
-        if kwargs:
-            self.update(kwargs)
-    
-    def reset(self):
-        """Reset self to default values."""
-        self.clear()
-        dict.update(self, self.defaults)
-    
-    def update(self, config):
-        """Update self from a dict, file or filename."""
-        if isinstance(config, basestring):
-            # Filename
-            config = Parser().dict_from_file(config)
-        elif hasattr(config, 'read'):
-            # Open file object
-            config = Parser().dict_from_file(config)
-        else:
-            config = config.copy()
-        self._apply(config)
-    
-    def _apply(self, config):
-        """Update self from a dict."""
-        which_env = config.get('environment')
-        if which_env:
-            env = self.environments[which_env]
-            for k in env:
-                if k not in config:
-                    config[k] = env[k]
-        
-        dict.update(self, config)
-        self.namespaces(config)
-    
-    def __setitem__(self, k, v):
-        dict.__setitem__(self, k, v)
-        self.namespaces({k: v})
-
-
-class Parser(ConfigParser):
-    """Sub-class of ConfigParser that keeps the case of options and that raises
-    an exception if the file cannot be read.
-    """
-    
-    def optionxform(self, optionstr):
-        return optionstr
-    
-    def read(self, filenames):
-        if isinstance(filenames, basestring):
-            filenames = [filenames]
-        for filename in filenames:
-            # try:
-            #     fp = open(filename)
-            # except IOError:
-            #     continue
-            fp = open(filename)
-            try:
-                self._read(fp, filename)
-            finally:
-                fp.close()
-    
-    def as_dict(self, raw=False, vars=None):
-        """Convert an INI file to a dictionary"""
-        # Load INI file into a dict
-        result = {}
-        for section in self.sections():
-            if section not in result:
-                result[section] = {}
-            for option in self.options(section):
-                value = self.get(section, option, raw, vars)
-                try:
-                    value = unrepr(value)
-                except Exception, x:
-                    msg = ("Config error in section: %r, option: %r, "
-                           "value: %r. Config values must be valid Python." %
-                           (section, option, value))
-                    raise ValueError(msg, x.__class__.__name__, x.args)
-                result[section][option] = value
-        return result
-    
-    def dict_from_file(self, file):
-        if hasattr(file, 'read'):
-            self.readfp(file)
-        else:
-            self.read(file)
-        return self.as_dict()
-
-
-# public domain "unrepr" implementation, found on the web and then improved.
-
-class _Builder:
-    
-    def build(self, o):
-        m = getattr(self, 'build_' + o.__class__.__name__, None)
-        if m is None:
-            raise TypeError("unrepr does not recognize %s" %
-                            repr(o.__class__.__name__))
-        return m(o)
-    
-    def build_Subscript(self, o):
-        expr, flags, subs = o.getChildren()
-        expr = self.build(expr)
-        subs = self.build(subs)
-        return expr[subs]
-    
-    def build_CallFunc(self, o):
-        children = map(self.build, o.getChildren())
-        callee = children.pop(0)
-        kwargs = children.pop() or {}
-        starargs = children.pop() or ()
-        args = tuple(children) + tuple(starargs)
-        return callee(*args, **kwargs)
-    
-    def build_List(self, o):
-        return map(self.build, o.getChildren())
-    
-    def build_Const(self, o):
-        return o.value
-    
-    def build_Dict(self, o):
-        d = {}
-        i = iter(map(self.build, o.getChildren()))
-        for el in i:
-            d[el] = i.next()
-        return d
-    
-    def build_Tuple(self, o):
-        return tuple(self.build_List(o))
-    
-    def build_Name(self, o):
-        name = o.name
-        if name == 'None':
-            return None
-        if name == 'True':
-            return True
-        if name == 'False':
-            return False
-        
-        # See if the Name is a package or module. If it is, import it.
-        try:
-            return modules(name)
-        except ImportError:
-            pass
-        
-        # See if the Name is in builtins.
-        try:
-            import __builtin__
-            return getattr(__builtin__, name)
-        except AttributeError:
-            pass
-        
-        raise TypeError("unrepr could not resolve the name %s" % repr(name))
-    
-    def build_Add(self, o):
-        left, right = map(self.build, o.getChildren())
-        return left + right
-    
-    def build_Getattr(self, o):
-        parent = self.build(o.expr)
-        return getattr(parent, o.attrname)
-    
-    def build_NoneType(self, o):
-        return None
-    
-    def build_UnarySub(self, o):
-        return -self.build(o.getChildren()[0])
-    
-    def build_UnaryAdd(self, o):
-        return self.build(o.getChildren()[0])
-
-
-def _astnode(s):
-    """Return a Python ast Node compiled from a string."""
-    try:
-        import compiler
-    except ImportError:
-        # Fallback to eval when compiler package is not available,
-        # e.g. IronPython 1.0.
-        return eval(s)
-    
-    p = compiler.parse("__tempvalue__ = " + s)
-    return p.getChildren()[1].getChildren()[0].getChildren()[1]
-    
-
-def unrepr(s):
-    """Return a Python object compiled from a string."""
-    if not s:
-        return s
-    obj = _astnode(s)
-    return _Builder().build(obj)
-
-
-def modules(modulePath):
-    """Load a module and retrieve a reference to that module."""
-    try:
-        mod = sys.modules[modulePath]
-        if mod is None:
-            raise KeyError()
-    except KeyError:
-        # The last [''] is important.
-        mod = __import__(modulePath, globals(), locals(), [''])
-    return mod
-
-def attributes(full_attribute_name):
-    """Load a module and retrieve an attribute of that module."""
-    
-    # Parse out the path, module, and attribute
-    last_dot = full_attribute_name.rfind(".")
-    attr_name = full_attribute_name[last_dot + 1:]
-    mod_path = full_attribute_name[:last_dot]
-    
-    mod = modules(mod_path)
-    # Let an AttributeError propagate outward.
-    try:
-        attr = getattr(mod, attr_name)
-    except AttributeError:
-        raise AttributeError("'%s' object has no attribute '%s'"
-                             % (mod_path, attr_name))
-    
-    # Return a reference to the attribute.
-    return attr
-
-
--- a/bundled/cherrypy/cherrypy/lib/sessions.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,741 +0,0 @@
-"""Session implementation for CherryPy.
-
-We use cherrypy.request to store some convenient variables as
-well as data about the session for the current request. Instead of
-polluting cherrypy.request we use a Session object bound to
-cherrypy.session to store these variables.
-"""
-
-import datetime
-import os
-try:
-    import cPickle as pickle
-except ImportError:
-    import pickle
-import random
-try:
-    # Python 2.5+
-    from hashlib import sha1 as sha
-except ImportError:
-    from sha import new as sha
-import time
-import threading
-import types
-from warnings import warn
-
-import cherrypy
-from cherrypy.lib import httputil
-
-
-missing = object()
-
-class Session(object):
-    """A CherryPy dict-like Session object (one per request)."""
-    
-    __metaclass__ = cherrypy._AttributeDocstrings
-    
-    _id = None
-    id_observers = None
-    id_observers__doc = "A list of callbacks to which to pass new id's."
-    
-    id__doc = "The current session ID."
-    def _get_id(self):
-        return self._id
-    def _set_id(self, value):
-        self._id = value
-        for o in self.id_observers:
-            o(value)
-    id = property(_get_id, _set_id, doc=id__doc)
-    
-    timeout = 60
-    timeout__doc = "Number of minutes after which to delete session data."
-    
-    locked = False
-    locked__doc = """
-    If True, this session instance has exclusive read/write access
-    to session data."""
-    
-    loaded = False
-    loaded__doc = """
-    If True, data has been retrieved from storage. This should happen
-    automatically on the first attempt to access session data."""
-    
-    clean_thread = None
-    clean_thread__doc = "Class-level Monitor which calls self.clean_up."
-    
-    clean_freq = 5
-    clean_freq__doc = "The poll rate for expired session cleanup in minutes."
-    
-    originalid = None
-    originalid__doc = "The session id passed by the client. May be missing or unsafe."
-    
-    missing = False
-    missing__doc = "True if the session requested by the client did not exist."
-    
-    regenerated = False
-    regenerated__doc = """
-    True if the application called session.regenerate(). This is not set by
-    internal calls to regenerate the session id."""
-    
-    debug=False
-    
-    def __init__(self, id=None, **kwargs):
-        self.id_observers = []
-        self._data = {}
-        
-        for k, v in kwargs.items():
-            setattr(self, k, v)
-        
-        self.originalid = id
-        self.missing = False
-        if id is None:
-            if self.debug:
-                cherrypy.log('No id given; making a new one', 'TOOLS.SESSIONS')
-            self._regenerate()
-        else:
-            self.id = id
-            if not self._exists():
-                if self.debug:
-                    cherrypy.log('Expired or malicious session %r; '
-                                 'making a new one' % id, 'TOOLS.SESSIONS')
-                # Expired or malicious session. Make a new one.
-                # See http://www.cherrypy.org/ticket/709.
-                self.id = None
-                self.missing = True
-                self._regenerate()
-    
-    def regenerate(self):
-        """Replace the current session (with a new id)."""
-        self.regenerated = True
-        self._regenerate()
-    
-    def _regenerate(self):
-        if self.id is not None:
-            self.delete()
-        
-        old_session_was_locked = self.locked
-        if old_session_was_locked:
-            self.release_lock()
-        
-        self.id = None
-        while self.id is None:
-            self.id = self.generate_id()
-            # Assert that the generated id is not already stored.
-            if self._exists():
-                self.id = None
-        
-        if old_session_was_locked:
-            self.acquire_lock()
-    
-    def clean_up(self):
-        """Clean up expired sessions."""
-        pass
-    
-    try:
-        os.urandom(20)
-    except (AttributeError, NotImplementedError):
-        # os.urandom not available until Python 2.4. Fall back to random.random.
-        def generate_id(self):
-            """Return a new session id."""
-            return sha('%s' % random.random()).hexdigest()
-    else:
-        def generate_id(self):
-            """Return a new session id."""
-            return os.urandom(20).encode('hex')
-    
-    def save(self):
-        """Save session data."""
-        try:
-            # If session data has never been loaded then it's never been
-            #   accessed: no need to save it
-            if self.loaded:
-                t = datetime.timedelta(seconds = self.timeout * 60)
-                expiration_time = datetime.datetime.now() + t
-                if self.debug:
-                    cherrypy.log('Saving with expiry %s' % expiration_time,
-                                 'TOOLS.SESSIONS')
-                self._save(expiration_time)
-            
-        finally:
-            if self.locked:
-                # Always release the lock if the user didn't release it
-                self.release_lock()
-    
-    def load(self):
-        """Copy stored session data into this session instance."""
-        data = self._load()
-        # data is either None or a tuple (session_data, expiration_time)
-        if data is None or data[1] < datetime.datetime.now():
-            if self.debug:
-                cherrypy.log('Expired session, flushing data', 'TOOLS.SESSIONS')
-            self._data = {}
-        else:
-            self._data = data[0]
-        self.loaded = True
-        
-        # Stick the clean_thread in the class, not the instance.
-        # The instances are created and destroyed per-request.
-        cls = self.__class__
-        if self.clean_freq and not cls.clean_thread:
-            # clean_up is in instancemethod and not a classmethod,
-            # so that tool config can be accessed inside the method.
-            t = cherrypy.process.plugins.Monitor(
-                cherrypy.engine, self.clean_up, self.clean_freq * 60,
-                name='Session cleanup')
-            t.subscribe()
-            cls.clean_thread = t
-            t.start()
-    
-    def delete(self):
-        """Delete stored session data."""
-        self._delete()
-    
-    def __getitem__(self, key):
-        if not self.loaded: self.load()
-        return self._data[key]
-    
-    def __setitem__(self, key, value):
-        if not self.loaded: self.load()
-        self._data[key] = value
-    
-    def __delitem__(self, key):
-        if not self.loaded: self.load()
-        del self._data[key]
-    
-    def pop(self, key, default=missing):
-        """Remove the specified key and return the corresponding value.
-        If key is not found, default is returned if given,
-        otherwise KeyError is raised.
-        """
-        if not self.loaded: self.load()
-        if default is missing:
-            return self._data.pop(key)
-        else:
-            return self._data.pop(key, default)
-    
-    def __contains__(self, key):
-        if not self.loaded: self.load()
-        return key in self._data
-    
-    def has_key(self, key):
-        """D.has_key(k) -> True if D has a key k, else False."""
-        if not self.loaded: self.load()
-        return key in self._data
-    
-    def get(self, key, default=None):
-        """D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None."""
-        if not self.loaded: self.load()
-        return self._data.get(key, default)
-    
-    def update(self, d):
-        """D.update(E) -> None.  Update D from E: for k in E: D[k] = E[k]."""
-        if not self.loaded: self.load()
-        self._data.update(d)
-    
-    def setdefault(self, key, default=None):
-        """D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D."""
-        if not self.loaded: self.load()
-        return self._data.setdefault(key, default)
-    
-    def clear(self):
-        """D.clear() -> None.  Remove all items from D."""
-        if not self.loaded: self.load()
-        self._data.clear()
-    
-    def keys(self):
-        """D.keys() -> list of D's keys."""
-        if not self.loaded: self.load()
-        return self._data.keys()
-    
-    def items(self):
-        """D.items() -> list of D's (key, value) pairs, as 2-tuples."""
-        if not self.loaded: self.load()
-        return self._data.items()
-    
-    def values(self):
-        """D.values() -> list of D's values."""
-        if not self.loaded: self.load()
-        return self._data.values()
-
-
-class RamSession(Session):
-    
-    # Class-level objects. Don't rebind these!
-    cache = {}
-    locks = {}
-    
-    def clean_up(self):
-        """Clean up expired sessions."""
-        now = datetime.datetime.now()
-        for id, (data, expiration_time) in self.cache.items():
-            if expiration_time <= now:
-                try:
-                    del self.cache[id]
-                except KeyError:
-                    pass
-                try:
-                    del self.locks[id]
-                except KeyError:
-                    pass
-    
-    def _exists(self):
-        return self.id in self.cache
-    
-    def _load(self):
-        return self.cache.get(self.id)
-    
-    def _save(self, expiration_time):
-        self.cache[self.id] = (self._data, expiration_time)
-    
-    def _delete(self):
-        self.cache.pop(self.id, None)
-    
-    def acquire_lock(self):
-        """Acquire an exclusive lock on the currently-loaded session data."""
-        self.locked = True
-        self.locks.setdefault(self.id, threading.RLock()).acquire()
-    
-    def release_lock(self):
-        """Release the lock on the currently-loaded session data."""
-        self.locks[self.id].release()
-        self.locked = False
-    
-    def __len__(self):
-        """Return the number of active sessions."""
-        return len(self.cache)
-
-
-class FileSession(Session):
-    """Implementation of the File backend for sessions
-    
-    storage_path: the folder where session data will be saved. Each session
-        will be saved as pickle.dump(data, expiration_time) in its own file;
-        the filename will be self.SESSION_PREFIX + self.id.
-    """
-    
-    SESSION_PREFIX = 'session-'
-    LOCK_SUFFIX = '.lock'
-    pickle_protocol = pickle.HIGHEST_PROTOCOL
-    
-    def __init__(self, id=None, **kwargs):
-        # The 'storage_path' arg is required for file-based sessions.
-        kwargs['storage_path'] = os.path.abspath(kwargs['storage_path'])
-        Session.__init__(self, id=id, **kwargs)
-    
-    def setup(cls, **kwargs):
-        """Set up the storage system for file-based sessions.
-        
-        This should only be called once per process; this will be done
-        automatically when using sessions.init (as the built-in Tool does).
-        """
-        # The 'storage_path' arg is required for file-based sessions.
-        kwargs['storage_path'] = os.path.abspath(kwargs['storage_path'])
-        
-        for k, v in kwargs.items():
-            setattr(cls, k, v)
-        
-        # Warn if any lock files exist at startup.
-        lockfiles = [fname for fname in os.listdir(cls.storage_path)
-                     if (fname.startswith(cls.SESSION_PREFIX)
-                         and fname.endswith(cls.LOCK_SUFFIX))]
-        if lockfiles:
-            plural = ('', 's')[len(lockfiles) > 1]
-            warn("%s session lockfile%s found at startup. If you are "
-                 "only running one process, then you may need to "
-                 "manually delete the lockfiles found at %r."
-                 % (len(lockfiles), plural, cls.storage_path))
-    setup = classmethod(setup)
-    
-    def _get_file_path(self):
-        f = os.path.join(self.storage_path, self.SESSION_PREFIX + self.id)
-        if not os.path.abspath(f).startswith(self.storage_path):
-            raise cherrypy.HTTPError(400, "Invalid session id in cookie.")
-        return f
-    
-    def _exists(self):
-        path = self._get_file_path()
-        return os.path.exists(path)
-    
-    def _load(self, path=None):
-        if path is None:
-            path = self._get_file_path()
-        try:
-            f = open(path, "rb")
-            try:
-                return pickle.load(f)
-            finally:
-                f.close()
-        except (IOError, EOFError):
-            return None
-    
-    def _save(self, expiration_time):
-        f = open(self._get_file_path(), "wb")
-        try:
-            pickle.dump((self._data, expiration_time), f, self.pickle_protocol)
-        finally:
-            f.close()
-    
-    def _delete(self):
-        try:
-            os.unlink(self._get_file_path())
-        except OSError:
-            pass
-    
-    def acquire_lock(self, path=None):
-        """Acquire an exclusive lock on the currently-loaded session data."""
-        if path is None:
-            path = self._get_file_path()
-        path += self.LOCK_SUFFIX
-        while True:
-            try:
-                lockfd = os.open(path, os.O_CREAT|os.O_WRONLY|os.O_EXCL)
-            except OSError:
-                time.sleep(0.1)
-            else:
-                os.close(lockfd) 
-                break
-        self.locked = True
-    
-    def release_lock(self, path=None):
-        """Release the lock on the currently-loaded session data."""
-        if path is None:
-            path = self._get_file_path()
-        os.unlink(path + self.LOCK_SUFFIX)
-        self.locked = False
-    
-    def clean_up(self):
-        """Clean up expired sessions."""
-        now = datetime.datetime.now()
-        # Iterate over all session files in self.storage_path
-        for fname in os.listdir(self.storage_path):
-            if (fname.startswith(self.SESSION_PREFIX)
-                and not fname.endswith(self.LOCK_SUFFIX)):
-                # We have a session file: lock and load it and check
-                #   if it's expired. If it fails, nevermind.
-                path = os.path.join(self.storage_path, fname)
-                self.acquire_lock(path)
-                try:
-                    contents = self._load(path)
-                    # _load returns None on IOError
-                    if contents is not None:
-                        data, expiration_time = contents
-                        if expiration_time < now:
-                            # Session expired: deleting it
-                            os.unlink(path)
-                finally:
-                    self.release_lock(path)
-    
-    def __len__(self):
-        """Return the number of active sessions."""
-        return len([fname for fname in os.listdir(self.storage_path)
-                    if (fname.startswith(self.SESSION_PREFIX)
-                        and not fname.endswith(self.LOCK_SUFFIX))])
-
-
-class PostgresqlSession(Session):
-    """ Implementation of the PostgreSQL backend for sessions. It assumes
-        a table like this:
-
-            create table session (
-                id varchar(40),
-                data text,
-                expiration_time timestamp
-            )
-    
-    You must provide your own get_db function.
-    """
-    
-    pickle_protocol = pickle.HIGHEST_PROTOCOL
-    
-    def __init__(self, id=None, **kwargs):
-        Session.__init__(self, id, **kwargs)
-        self.cursor = self.db.cursor()
-    
-    def setup(cls, **kwargs):
-        """Set up the storage system for Postgres-based sessions.
-        
-        This should only be called once per process; this will be done
-        automatically when using sessions.init (as the built-in Tool does).
-        """
-        for k, v in kwargs.items():
-            setattr(cls, k, v)
-        
-        self.db = self.get_db()
-    setup = classmethod(setup)
-    
-    def __del__(self):
-        if self.cursor:
-            self.cursor.close()
-        self.db.commit()
-    
-    def _exists(self):
-        # Select session data from table
-        self.cursor.execute('select data, expiration_time from session '
-                            'where id=%s', (self.id,))
-        rows = self.cursor.fetchall()
-        return bool(rows)
-    
-    def _load(self):
-        # Select session data from table
-        self.cursor.execute('select data, expiration_time from session '
-                            'where id=%s', (self.id,))
-        rows = self.cursor.fetchall()
-        if not rows:
-            return None
-        
-        pickled_data, expiration_time = rows[0]
-        data = pickle.loads(pickled_data)
-        return data, expiration_time
-    
-    def _save(self, expiration_time):
-        pickled_data = pickle.dumps(self._data, self.pickle_protocol)
-        self.cursor.execute('update session set data = %s, '
-                            'expiration_time = %s where id = %s',
-                            (pickled_data, expiration_time, self.id))
-    
-    def _delete(self):
-        self.cursor.execute('delete from session where id=%s', (self.id,))
-   
-    def acquire_lock(self):
-        """Acquire an exclusive lock on the currently-loaded session data."""
-        # We use the "for update" clause to lock the row
-        self.locked = True
-        self.cursor.execute('select id from session where id=%s for update',
-                            (self.id,))
-    
-    def release_lock(self):
-        """Release the lock on the currently-loaded session data."""
-        # We just close the cursor and that will remove the lock
-        #   introduced by the "for update" clause
-        self.cursor.close()
-        self.locked = False
-    
-    def clean_up(self):
-        """Clean up expired sessions."""
-        self.cursor.execute('delete from session where expiration_time < %s',
-                            (datetime.datetime.now(),))
-
-
-class MemcachedSession(Session):
-    
-    # The most popular memcached client for Python isn't thread-safe.
-    # Wrap all .get and .set operations in a single lock.
-    mc_lock = threading.RLock()
-    
-    # This is a seperate set of locks per session id.
-    locks = {}
-    
-    servers = ['127.0.0.1:11211']
-    
-    def setup(cls, **kwargs):
-        """Set up the storage system for memcached-based sessions.
-        
-        This should only be called once per process; this will be done
-        automatically when using sessions.init (as the built-in Tool does).
-        """
-        for k, v in kwargs.items():
-            setattr(cls, k, v)
-        
-        import memcache
-        cls.cache = memcache.Client(cls.servers)
-    setup = classmethod(setup)
-    
-    def _exists(self):
-        self.mc_lock.acquire()
-        try:
-            return bool(self.cache.get(self.id))
-        finally:
-            self.mc_lock.release()
-    
-    def _load(self):
-        self.mc_lock.acquire()
-        try:
-            return self.cache.get(self.id)
-        finally:
-            self.mc_lock.release()
-    
-    def _save(self, expiration_time):
-        # Send the expiration time as "Unix time" (seconds since 1/1/1970)
-        td = int(time.mktime(expiration_time.timetuple()))
-        self.mc_lock.acquire()
-        try:
-            if not self.cache.set(self.id, (self._data, expiration_time), td):
-                raise AssertionError("Session data for id %r not set." % self.id)
-        finally:
-            self.mc_lock.release()
-    
-    def _delete(self):
-        self.cache.delete(self.id)
-    
-    def acquire_lock(self):
-        """Acquire an exclusive lock on the currently-loaded session data."""
-        self.locked = True
-        self.locks.setdefault(self.id, threading.RLock()).acquire()
-    
-    def release_lock(self):
-        """Release the lock on the currently-loaded session data."""
-        self.locks[self.id].release()
-        self.locked = False
-    
-    def __len__(self):
-        """Return the number of active sessions."""
-        raise NotImplementedError
-
-
-# Hook functions (for CherryPy tools)
-
-def save():
-    """Save any changed session data."""
-    
-    if not hasattr(cherrypy.serving, "session"):
-        return
-    request = cherrypy.serving.request
-    response = cherrypy.serving.response
-    
-    # Guard against running twice
-    if hasattr(request, "_sessionsaved"):
-        return
-    request._sessionsaved = True
-    
-    if response.stream:
-        # If the body is being streamed, we have to save the data
-        #   *after* the response has been written out
-        request.hooks.attach('on_end_request', cherrypy.session.save)
-    else:
-        # If the body is not being streamed, we save the data now
-        # (so we can release the lock).
-        if isinstance(response.body, types.GeneratorType):
-            response.collapse_body()
-        cherrypy.session.save()
-save.failsafe = True
-
-def close():
-    """Close the session object for this request."""
-    sess = getattr(cherrypy.serving, "session", None)
-    if getattr(sess, "locked", False):
-        # If the session is still locked we release the lock
-        sess.release_lock()
-close.failsafe = True
-close.priority = 90
-
-
-def init(storage_type='ram', path=None, path_header=None, name='session_id',
-         timeout=60, domain=None, secure=False, clean_freq=5,
-         persistent=True, debug=False, **kwargs):
-    """Initialize session object (using cookies).
-    
-    storage_type: one of 'ram', 'file', 'postgresql'. This will be used
-        to look up the corresponding class in cherrypy.lib.sessions
-        globals. For example, 'file' will use the FileSession class.
-    path: the 'path' value to stick in the response cookie metadata.
-    path_header: if 'path' is None (the default), then the response
-        cookie 'path' will be pulled from request.headers[path_header].
-    name: the name of the cookie.
-    timeout: the expiration timeout (in minutes) for the stored session data.
-        If 'persistent' is True (the default), this is also the timeout
-        for the cookie.
-    domain: the cookie domain.
-    secure: if False (the default) the cookie 'secure' value will not
-        be set. If True, the cookie 'secure' value will be set (to 1).
-    clean_freq (minutes): the poll rate for expired session cleanup.
-    persistent: if True (the default), the 'timeout' argument will be used
-        to expire the cookie. If False, the cookie will not have an expiry,
-        and the cookie will be a "session cookie" which expires when the
-        browser is closed.
-    
-    Any additional kwargs will be bound to the new Session instance,
-    and may be specific to the storage type. See the subclass of Session
-    you're using for more information.
-    """
-    
-    request = cherrypy.serving.request
-    
-    # Guard against running twice
-    if hasattr(request, "_session_init_flag"):
-        return
-    request._session_init_flag = True
-    
-    # Check if request came with a session ID
-    id = None
-    if name in request.cookie:
-        id = request.cookie[name].value
-        if debug:
-            cherrypy.log('ID obtained from request.cookie: %r' % id,
-                         'TOOLS.SESSIONS')
-    
-    # Find the storage class and call setup (first time only).
-    storage_class = storage_type.title() + 'Session'
-    storage_class = globals()[storage_class]
-    if not hasattr(cherrypy, "session"):
-        if hasattr(storage_class, "setup"):
-            storage_class.setup(**kwargs)
-    
-    # Create and attach a new Session instance to cherrypy.serving.
-    # It will possess a reference to (and lock, and lazily load)
-    # the requested session data.
-    kwargs['timeout'] = timeout
-    kwargs['clean_freq'] = clean_freq
-    cherrypy.serving.session = sess = storage_class(id, **kwargs)
-    sess.debug = debug
-    def update_cookie(id):
-        """Update the cookie every time the session id changes."""
-        cherrypy.serving.response.cookie[name] = id
-    sess.id_observers.append(update_cookie)
-    
-    # Create cherrypy.session which will proxy to cherrypy.serving.session
-    if not hasattr(cherrypy, "session"):
-        cherrypy.session = cherrypy._ThreadLocalProxy('session')
-    
-    if persistent:
-        cookie_timeout = timeout
-    else:
-        # See http://support.microsoft.com/kb/223799/EN-US/
-        # and http://support.mozilla.com/en-US/kb/Cookies
-        cookie_timeout = None
-    set_response_cookie(path=path, path_header=path_header, name=name,
-                        timeout=cookie_timeout, domain=domain, secure=secure)
-
-
-def set_response_cookie(path=None, path_header=None, name='session_id',
-                        timeout=60, domain=None, secure=False):
-    """Set a response cookie for the client.
-    
-    path: the 'path' value to stick in the response cookie metadata.
-    path_header: if 'path' is None (the default), then the response
-        cookie 'path' will be pulled from request.headers[path_header].
-    name: the name of the cookie.
-    timeout: the expiration timeout for the cookie. If 0 or other boolean
-        False, no 'expires' param will be set, and the cookie will be a
-        "session cookie" which expires when the browser is closed.
-    domain: the cookie domain.
-    secure: if False (the default) the cookie 'secure' value will not
-        be set. If True, the cookie 'secure' value will be set (to 1).
-    """
-    # Set response cookie
-    cookie = cherrypy.serving.response.cookie
-    cookie[name] = cherrypy.serving.session.id
-    cookie[name]['path'] = (path or cherrypy.serving.request.headers.get(path_header)
-                            or '/')
-    
-    # We'd like to use the "max-age" param as indicated in
-    # http://www.faqs.org/rfcs/rfc2109.html but IE doesn't
-    # save it to disk and the session is lost if people close
-    # the browser. So we have to use the old "expires" ... sigh ...
-##    cookie[name]['max-age'] = timeout * 60
-    if timeout:
-        e = time.time() + (timeout * 60)
-        cookie[name]['expires'] = httputil.HTTPDate(e)
-    if domain is not None:
-        cookie[name]['domain'] = domain
-    if secure:
-        cookie[name]['secure'] = 1
-
-
-def expire():
-    """Expire the current session cookie."""
-    name = cherrypy.serving.request.config.get('tools.sessions.name', 'session_id')
-    one_year = 60 * 60 * 24 * 365
-    e = time.time() - one_year
-    cherrypy.serving.response.cookie[name]['expires'] = httputil.HTTPDate(e)
-
-
--- a/bundled/cherrypy/cherrypy/lib/static.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,346 +0,0 @@
-import logging
-import mimetypes
-mimetypes.init()
-mimetypes.types_map['.dwg']='image/x-dwg'
-mimetypes.types_map['.ico']='image/x-icon'
-mimetypes.types_map['.bz2']='application/x-bzip2'
-mimetypes.types_map['.gz']='application/x-gzip'
-
-import os
-import re
-import stat
-import time
-from urllib import unquote
-
-import cherrypy
-from cherrypy.lib import cptools, httputil, file_generator_limited
-
-
-def serve_file(path, content_type=None, disposition=None, name=None, debug=False):
-    """Set status, headers, and body in order to serve the given path.
-    
-    The Content-Type header will be set to the content_type arg, if provided.
-    If not provided, the Content-Type will be guessed by the file extension
-    of the 'path' argument.
-    
-    If disposition is not None, the Content-Disposition header will be set
-    to "<disposition>; filename=<name>". If name is None, it will be set
-    to the basename of path. If disposition is None, no Content-Disposition
-    header will be written.
-    """
-    
-    response = cherrypy.serving.response
-    
-    # If path is relative, users should fix it by making path absolute.
-    # That is, CherryPy should not guess where the application root is.
-    # It certainly should *not* use cwd (since CP may be invoked from a
-    # variety of paths). If using tools.staticdir, you can make your relative
-    # paths become absolute by supplying a value for "tools.staticdir.root".
-    if not os.path.isabs(path):
-        msg = "'%s' is not an absolute path." % path
-        if debug:
-            cherrypy.log(msg, 'TOOLS.STATICFILE')
-        raise ValueError(msg)
-    
-    try:
-        st = os.stat(path)
-    except OSError:
-        if debug:
-            cherrypy.log('os.stat(%r) failed' % path, 'TOOLS.STATIC')
-        raise cherrypy.NotFound()
-    
-    # Check if path is a directory.
-    if stat.S_ISDIR(st.st_mode):
-        # Let the caller deal with it as they like.
-        if debug:
-            cherrypy.log('%r is a directory' % path, 'TOOLS.STATIC')
-        raise cherrypy.NotFound()
-    
-    # Set the Last-Modified response header, so that
-    # modified-since validation code can work.
-    response.headers['Last-Modified'] = httputil.HTTPDate(st.st_mtime)
-    cptools.validate_since()
-    
-    if content_type is None:
-        # Set content-type based on filename extension
-        ext = ""
-        i = path.rfind('.')
-        if i != -1:
-            ext = path[i:].lower()
-        content_type = mimetypes.types_map.get(ext, None)
-    if content_type is not None:
-        response.headers['Content-Type'] = content_type
-    if debug:
-        cherrypy.log('Content-Type: %r' % content_type, 'TOOLS.STATIC')
-    
-    cd = None
-    if disposition is not None:
-        if name is None:
-            name = os.path.basename(path)
-        cd = '%s; filename="%s"' % (disposition, name)
-        response.headers["Content-Disposition"] = cd
-    if debug:
-        cherrypy.log('Content-Disposition: %r' % cd, 'TOOLS.STATIC')
-    
-    # Set Content-Length and use an iterable (file object)
-    #   this way CP won't load the whole file in memory
-    content_length = st.st_size
-    fileobj = open(path, 'rb')
-    return _serve_fileobj(fileobj, content_type, content_length, debug=debug)
-
-def serve_fileobj(fileobj, content_type=None, disposition=None, name=None,
-                  debug=False):
-    """Set status, headers, and body in order to serve the given file object.
-    
-    The Content-Type header will be set to the content_type arg, if provided.
-    
-    If disposition is not None, the Content-Disposition header will be set
-    to "<disposition>; filename=<name>". If name is None, 'filename' will
-    not be set. If disposition is None, no Content-Disposition header will
-    be written.
-
-    CAUTION: If the request contains a 'Range' header, one or more seek()s will
-    be performed on the file object.  This may cause undesired behavior if
-    the file object is not seekable.  It could also produce undesired results
-    if the caller set the read position of the file object prior to calling
-    serve_fileobj(), expecting that the data would be served starting from that
-    position.
-    """
-    
-    response = cherrypy.serving.response
-    
-    try:
-        st = os.fstat(fileobj.fileno())
-    except AttributeError:
-        if debug:
-            cherrypy.log('os has no fstat attribute', 'TOOLS.STATIC')
-        content_length = None
-    else:
-        # Set the Last-Modified response header, so that
-        # modified-since validation code can work.
-        response.headers['Last-Modified'] = httputil.HTTPDate(st.st_mtime)
-        cptools.validate_since()
-        content_length = st.st_size
-    
-    if content_type is not None:
-        response.headers['Content-Type'] = content_type
-    if debug:
-        cherrypy.log('Content-Type: %r' % content_type, 'TOOLS.STATIC')
-    
-    cd = None
-    if disposition is not None:
-        if name is None:
-            cd = disposition
-        else:
-            cd = '%s; filename="%s"' % (disposition, name)
-        response.headers["Content-Disposition"] = cd
-    if debug:
-        cherrypy.log('Content-Disposition: %r' % cd, 'TOOLS.STATIC')
-    
-    return _serve_fileobj(fileobj, content_type, content_length, debug=debug)
-
-def _serve_fileobj(fileobj, content_type, content_length, debug=False):
-    """Internal. Set response.body to the given file object, perhaps ranged."""
-    response = cherrypy.serving.response
-    
-    # HTTP/1.0 didn't have Range/Accept-Ranges headers, or the 206 code
-    request = cherrypy.serving.request
-    if request.protocol >= (1, 1):
-        response.headers["Accept-Ranges"] = "bytes"
-        r = httputil.get_ranges(request.headers.get('Range'), content_length)
-        if r == []:
-            response.headers['Content-Range'] = "bytes */%s" % content_length
-            message = "Invalid Range (first-byte-pos greater than Content-Length)"
-            if debug:
-                cherrypy.log(message, 'TOOLS.STATIC')
-            raise cherrypy.HTTPError(416, message)
-        
-        if r:
-            if len(r) == 1:
-                # Return a single-part response.
-                start, stop = r[0]
-                if stop > content_length:
-                    stop = content_length
-                r_len = stop - start
-                if debug:
-                    cherrypy.log('Single part; start: %r, stop: %r' % (start, stop),
-                                 'TOOLS.STATIC')
-                response.status = "206 Partial Content"
-                response.headers['Content-Range'] = (
-                    "bytes %s-%s/%s" % (start, stop - 1, content_length))
-                response.headers['Content-Length'] = r_len
-                fileobj.seek(start)
-                response.body = file_generator_limited(fileobj, r_len)
-            else:
-                # Return a multipart/byteranges response.
-                response.status = "206 Partial Content"
-                import mimetools
-                boundary = mimetools.choose_boundary()
-                ct = "multipart/byteranges; boundary=%s" % boundary
-                response.headers['Content-Type'] = ct
-                if "Content-Length" in response.headers:
-                    # Delete Content-Length header so finalize() recalcs it.
-                    del response.headers["Content-Length"]
-                
-                def file_ranges():
-                    # Apache compatibility:
-                    yield "\r\n"
-                    
-                    for start, stop in r:
-                        if debug:
-                            cherrypy.log('Multipart; start: %r, stop: %r' % (start, stop),
-                                         'TOOLS.STATIC')
-                        yield "--" + boundary
-                        yield "\r\nContent-type: %s" % content_type
-                        yield ("\r\nContent-range: bytes %s-%s/%s\r\n\r\n"
-                               % (start, stop - 1, content_length))
-                        fileobj.seek(start)
-                        for chunk in file_generator_limited(fileobj, stop-start):
-                            yield chunk
-                        yield "\r\n"
-                    # Final boundary
-                    yield "--" + boundary + "--"
-                    
-                    # Apache compatibility:
-                    yield "\r\n"
-                response.body = file_ranges()
-            return response.body
-        else:
-            if debug:
-                cherrypy.log('No byteranges requested', 'TOOLS.STATIC')
-    
-    # Set Content-Length and use an iterable (file object)
-    #   this way CP won't load the whole file in memory
-    response.headers['Content-Length'] = content_length
-    response.body = fileobj
-    return response.body
-
-def serve_download(path, name=None):
-    """Serve 'path' as an application/x-download attachment."""
-    # This is such a common idiom I felt it deserved its own wrapper.
-    return serve_file(path, "application/x-download", "attachment", name)
-
-
-def _attempt(filename, content_types, debug=False):
-    if debug:
-        cherrypy.log('Attempting %r (content_types %r)' %
-                     (filename, content_types), 'TOOLS.STATICDIR')
-    try:
-        # you can set the content types for a
-        # complete directory per extension
-        content_type = None
-        if content_types:
-            r, ext = os.path.splitext(filename)
-            content_type = content_types.get(ext[1:], None)
-        serve_file(filename, content_type=content_type, debug=debug)
-        return True
-    except cherrypy.NotFound:
-        # If we didn't find the static file, continue handling the
-        # request. We might find a dynamic handler instead.
-        if debug:
-            cherrypy.log('NotFound', 'TOOLS.STATICFILE')
-        return False
-
-def staticdir(section, dir, root="", match="", content_types=None, index="",
-              debug=False):
-    """Serve a static resource from the given (root +) dir.
-    
-    If 'match' is given, request.path_info will be searched for the given
-    regular expression before attempting to serve static content.
-    
-    If content_types is given, it should be a Python dictionary of
-    {file-extension: content-type} pairs, where 'file-extension' is
-    a string (e.g. "gif") and 'content-type' is the value to write
-    out in the Content-Type response header (e.g. "image/gif").
-    
-    If 'index' is provided, it should be the (relative) name of a file to
-    serve for directory requests. For example, if the dir argument is
-    '/home/me', the Request-URI is 'myapp', and the index arg is
-    'index.html', the file '/home/me/myapp/index.html' will be sought.
-    """
-    request = cherrypy.serving.request
-    if request.method not in ('GET', 'HEAD'):
-        if debug:
-            cherrypy.log('request.method not GET or HEAD', 'TOOLS.STATICDIR')
-        return False
-    
-    if match and not re.search(match, request.path_info):
-        if debug:
-            cherrypy.log('request.path_info %r does not match pattern %r' %
-                         (request.path_info, match), 'TOOLS.STATICDIR')
-        return False
-    
-    # Allow the use of '~' to refer to a user's home directory.
-    dir = os.path.expanduser(dir)
-
-    # If dir is relative, make absolute using "root".
-    if not os.path.isabs(dir):
-        if not root:
-            msg = "Static dir requires an absolute dir (or root)."
-            if debug:
-                cherrypy.log(msg, 'TOOLS.STATICDIR')
-            raise ValueError(msg)
-        dir = os.path.join(root, dir)
-    
-    # Determine where we are in the object tree relative to 'section'
-    # (where the static tool was defined).
-    if section == 'global':
-        section = "/"
-    section = section.rstrip(r"\/")
-    branch = request.path_info[len(section) + 1:]
-    branch = unquote(branch.lstrip(r"\/"))
-    
-    # If branch is "", filename will end in a slash
-    filename = os.path.join(dir, branch)
-    if debug:
-        cherrypy.log('Checking file %r to fulfill %r' %
-                     (filename, request.path_info), 'TOOLS.STATICDIR')
-    
-    # There's a chance that the branch pulled from the URL might
-    # have ".." or similar uplevel attacks in it. Check that the final
-    # filename is a child of dir.
-    if not os.path.normpath(filename).startswith(os.path.normpath(dir)):
-        raise cherrypy.HTTPError(403) # Forbidden
-    
-    handled = _attempt(filename, content_types)
-    if not handled:
-        # Check for an index file if a folder was requested.
-        if index:
-            handled = _attempt(os.path.join(filename, index), content_types)
-            if handled:
-                request.is_index = filename[-1] in (r"\/")
-    return handled
-
-def staticfile(filename, root=None, match="", content_types=None, debug=False):
-    """Serve a static resource from the given (root +) filename.
-    
-    If 'match' is given, request.path_info will be searched for the given
-    regular expression before attempting to serve static content.
-    
-    If content_types is given, it should be a Python dictionary of
-    {file-extension: content-type} pairs, where 'file-extension' is
-    a string (e.g. "gif") and 'content-type' is the value to write
-    out in the Content-Type response header (e.g. "image/gif").
-    """
-    request = cherrypy.serving.request
-    if request.method not in ('GET', 'HEAD'):
-        if debug:
-            cherrypy.log('request.method not GET or HEAD', 'TOOLS.STATICFILE')
-        return False
-    
-    if match and not re.search(match, request.path_info):
-        if debug:
-            cherrypy.log('request.path_info %r does not match pattern %r' %
-                         (request.path_info, match), 'TOOLS.STATICFILE')
-        return False
-    
-    # If filename is relative, make absolute using "root".
-    if not os.path.isabs(filename):
-        if not root:
-            msg = "Static tool requires an absolute filename (got '%s')." % filename
-            if debug:
-                cherrypy.log(msg, 'TOOLS.STATICFILE')
-            raise ValueError(msg)
-        filename = os.path.join(root, filename)
-    
-    return _attempt(filename, content_types, debug=debug)
--- a/bundled/cherrypy/cherrypy/lib/xmlrpc.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-import sys
-
-import cherrypy
-
-
-def process_body():
-    """Return (params, method) from request body."""
-    try:
-        import xmlrpclib
-        return xmlrpclib.loads(cherrypy.request.body.read())
-    except Exception:
-        return ('ERROR PARAMS', ), 'ERRORMETHOD'
-
-
-def patched_path(path):
-    """Return 'path', doctored for RPC."""
-    if not path.endswith('/'):
-        path += '/'
-    if path.startswith('/RPC2/'):
-        # strip the first /rpc2
-        path = path[5:]
-    return path
-
-
-def _set_response(body):
-    # The XML-RPC spec (http://www.xmlrpc.com/spec) says:
-    # "Unless there's a lower-level error, always return 200 OK."
-    # Since Python's xmlrpclib interprets a non-200 response
-    # as a "Protocol Error", we'll just return 200 every time.
-    response = cherrypy.response
-    response.status = '200 OK'
-    response.body = body
-    response.headers['Content-Type'] = 'text/xml'
-    response.headers['Content-Length'] = len(body)
-
-
-def respond(body, encoding='utf-8', allow_none=0):
-    from xmlrpclib import Fault, dumps
-    if not isinstance(body, Fault):
-        body = (body,)
-    _set_response(dumps(body, methodresponse=1,
-                        encoding=encoding,
-                        allow_none=allow_none))
-
-def on_error(*args, **kwargs):
-    body = str(sys.exc_info()[1])
-    from xmlrpclib import Fault, dumps
-    _set_response(dumps(Fault(1, body)))
-
--- a/bundled/cherrypy/cherrypy/process/__init__.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-"""Site container for an HTTP server.
-
-A Web Site Process Bus object is used to connect applications, servers,
-and frameworks with site-wide services such as daemonization, process
-reload, signal handling, drop privileges, PID file management, logging
-for all of these, and many more.
-
-The 'plugins' module defines a few abstract and concrete services for
-use with the bus. Some use tool-specific channels; see the documentation
-for each class.
-"""
-
-from cherrypy.process.wspbus import bus
-from cherrypy.process import plugins, servers
--- a/bundled/cherrypy/cherrypy/process/plugins.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,562 +0,0 @@
-"""Site services for use with a Web Site Process Bus."""
-
-import os
-import re
-try:
-    set
-except NameError:
-    from sets import Set as set
-import signal as _signal
-import sys
-import time
-import thread
-import threading
-
-# _module__file__base is used by Autoreload to make
-# absolute any filenames retrieved from sys.modules which are not
-# already absolute paths.  This is to work around Python's quirk
-# of importing the startup script and using a relative filename
-# for it in sys.modules.
-#
-# Autoreload examines sys.modules afresh every time it runs. If an application
-# changes the current directory by executing os.chdir(), then the next time
-# Autoreload runs, it will not be able to find any filenames which are
-# not absolute paths, because the current directory is not the same as when the
-# module was first imported.  Autoreload will then wrongly conclude the file has
-# "changed", and initiate the shutdown/re-exec sequence.
-# See ticket #917.
-# For this workaround to have a decent probability of success, this module
-# needs to be imported as early as possible, before the app has much chance
-# to change the working directory.
-_module__file__base = os.getcwd()
-
-
-class SimplePlugin(object):
-    """Plugin base class which auto-subscribes methods for known channels."""
-    
-    def __init__(self, bus):
-        self.bus = bus
-    
-    def subscribe(self):
-        """Register this object as a (multi-channel) listener on the bus."""
-        for channel in self.bus.listeners:
-            # Subscribe self.start, self.exit, etc. if present.
-            method = getattr(self, channel, None)
-            if method is not None:
-                self.bus.subscribe(channel, method)
-    
-    def unsubscribe(self):
-        """Unregister this object as a listener on the bus."""
-        for channel in self.bus.listeners:
-            # Unsubscribe self.start, self.exit, etc. if present.
-            method = getattr(self, channel, None)
-            if method is not None:
-                self.bus.unsubscribe(channel, method)
-
-
-
-class SignalHandler(object):
-    """Register bus channels (and listeners) for system signals.
-    
-    By default, instantiating this object subscribes the following signals
-    and listeners:
-    
-        TERM: bus.exit
-        HUP : bus.restart
-        USR1: bus.graceful
-    """
-    
-    # Map from signal numbers to names
-    signals = {}
-    for k, v in vars(_signal).items():
-        if k.startswith('SIG') and not k.startswith('SIG_'):
-            signals[v] = k
-    del k, v
-    
-    def __init__(self, bus):
-        self.bus = bus
-        # Set default handlers
-        self.handlers = {'SIGTERM': self.bus.exit,
-                         'SIGHUP': self.handle_SIGHUP,
-                         'SIGUSR1': self.bus.graceful,
-                         }
-        
-        self._previous_handlers = {}
-    
-    def subscribe(self):
-        for sig, func in self.handlers.items():
-            try:
-                self.set_handler(sig, func)
-            except ValueError:
-                pass
-    
-    def unsubscribe(self):
-        for signum, handler in self._previous_handlers.items():
-            signame = self.signals[signum]
-            
-            if handler is None:
-                self.bus.log("Restoring %s handler to SIG_DFL." % signame)
-                handler = _signal.SIG_DFL
-            else:
-                self.bus.log("Restoring %s handler %r." % (signame, handler))
-            
-            try:
-                our_handler = _signal.signal(signum, handler)
-                if our_handler is None:
-                    self.bus.log("Restored old %s handler %r, but our "
-                                 "handler was not registered." %
-                                 (signame, handler), level=30)
-            except ValueError:
-                self.bus.log("Unable to restore %s handler %r." %
-                             (signame, handler), level=40, traceback=True)
-    
-    def set_handler(self, signal, listener=None):
-        """Subscribe a handler for the given signal (number or name).
-        
-        If the optional 'listener' argument is provided, it will be
-        subscribed as a listener for the given signal's channel.
-        
-        If the given signal name or number is not available on the current
-        platform, ValueError is raised.
-        """
-        if isinstance(signal, basestring):
-            signum = getattr(_signal, signal, None)
-            if signum is None:
-                raise ValueError("No such signal: %r" % signal)
-            signame = signal
-        else:
-            try:
-                signame = self.signals[signal]
-            except KeyError:
-                raise ValueError("No such signal: %r" % signal)
-            signum = signal
-        
-        prev = _signal.signal(signum, self._handle_signal)
-        self._previous_handlers[signum] = prev
-        
-        if listener is not None:
-            self.bus.log("Listening for %s." % signame)
-            self.bus.subscribe(signame, listener)
-    
-    def _handle_signal(self, signum=None, frame=None):
-        """Python signal handler (self.set_handler subscribes it for you)."""
-        signame = self.signals[signum]
-        self.bus.log("Caught signal %s." % signame)
-        self.bus.publish(signame)
-    
-    def handle_SIGHUP(self):
-        if os.isatty(sys.stdin.fileno()):
-            # not daemonized (may be foreground or background)
-            self.bus.log("SIGHUP caught but not daemonized. Exiting.")
-            self.bus.exit()
-        else:
-            self.bus.log("SIGHUP caught while daemonized. Restarting.")
-            self.bus.restart()
-
-
-try:
-    import pwd, grp
-except ImportError:
-    pwd, grp = None, None
-
-
-class DropPrivileges(SimplePlugin):
-    """Drop privileges. uid/gid arguments not available on Windows.
-    
-    Special thanks to Gavin Baker: http://antonym.org/node/100.
-    """
-    
-    def __init__(self, bus, umask=None, uid=None, gid=None):
-        SimplePlugin.__init__(self, bus)
-        self.finalized = False
-        self.uid = uid
-        self.gid = gid
-        self.umask = umask
-    
-    def _get_uid(self):
-        return self._uid
-    def _set_uid(self, val):
-        if val is not None:
-            if pwd is None:
-                self.bus.log("pwd module not available; ignoring uid.",
-                             level=30)
-                val = None
-            elif isinstance(val, basestring):
-                val = pwd.getpwnam(val)[2]
-        self._uid = val
-    uid = property(_get_uid, _set_uid, doc="The uid under which to run.")
-    
-    def _get_gid(self):
-        return self._gid
-    def _set_gid(self, val):
-        if val is not None:
-            if grp is None:
-                self.bus.log("grp module not available; ignoring gid.",
-                             level=30)
-                val = None
-            elif isinstance(val, basestring):
-                val = grp.getgrnam(val)[2]
-        self._gid = val
-    gid = property(_get_gid, _set_gid, doc="The gid under which to run.")
-    
-    def _get_umask(self):
-        return self._umask
-    def _set_umask(self, val):
-        if val is not None:
-            try:
-                os.umask
-            except AttributeError:
-                self.bus.log("umask function not available; ignoring umask.",
-                             level=30)
-                val = None
-        self._umask = val
-    umask = property(_get_umask, _set_umask, doc="The umask under which to run.")
-    
-    def start(self):
-        # uid/gid
-        def current_ids():
-            """Return the current (uid, gid) if available."""
-            name, group = None, None
-            if pwd:
-                name = pwd.getpwuid(os.getuid())[0]
-            if grp:
-                group = grp.getgrgid(os.getgid())[0]
-            return name, group
-        
-        if self.finalized:
-            if not (self.uid is None and self.gid is None):
-                self.bus.log('Already running as uid: %r gid: %r' %
-                             current_ids())
-        else:
-            if self.uid is None and self.gid is None:
-                if pwd or grp:
-                    self.bus.log('uid/gid not set', level=30)
-            else:
-                self.bus.log('Started as uid: %r gid: %r' % current_ids())
-                if self.gid is not None:
-                    os.setgid(self.gid)
-                if self.uid is not None:
-                    os.setuid(self.uid)
-                self.bus.log('Running as uid: %r gid: %r' % current_ids())
-        
-        # umask
-        if self.finalized:
-            if self.umask is not None:
-                self.bus.log('umask already set to: %03o' % self.umask)
-        else:
-            if self.umask is None:
-                self.bus.log('umask not set', level=30)
-            else:
-                old_umask = os.umask(self.umask)
-                self.bus.log('umask old: %03o, new: %03o' %
-                             (old_umask, self.umask))
-        
-        self.finalized = True
-    # This is slightly higher than the priority for server.start
-    # in order to facilitate the most common use: starting on a low
-    # port (which requires root) and then dropping to another user.
-    start.priority = 77
-
-
-class Daemonizer(SimplePlugin):
-    """Daemonize the running script.
-    
-    Use this with a Web Site Process Bus via:
-        
-        Daemonizer(bus).subscribe()
-    
-    When this component finishes, the process is completely decoupled from
-    the parent environment. Please note that when this component is used,
-    the return code from the parent process will still be 0 if a startup
-    error occurs in the forked children. Errors in the initial daemonizing
-    process still return proper exit codes. Therefore, if you use this
-    plugin to daemonize, don't use the return code as an accurate indicator
-    of whether the process fully started. In fact, that return code only
-    indicates if the process succesfully finished the first fork.
-    """
-    
-    def __init__(self, bus, stdin='/dev/null', stdout='/dev/null',
-                 stderr='/dev/null'):
-        SimplePlugin.__init__(self, bus)
-        self.stdin = stdin
-        self.stdout = stdout
-        self.stderr = stderr
-        self.finalized = False
-    
-    def start(self):
-        if self.finalized:
-            self.bus.log('Already deamonized.')
-        
-        # forking has issues with threads:
-        # http://www.opengroup.org/onlinepubs/000095399/functions/fork.html
-        # "The general problem with making fork() work in a multi-threaded
-        #  world is what to do with all of the threads..."
-        # So we check for active threads:
-        if threading.activeCount() != 1:
-            self.bus.log('There are %r active threads. '
-                         'Daemonizing now may cause strange failures.' %
-                         threading.enumerate(), level=30)
-        
-        # See http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
-        # (or http://www.faqs.org/faqs/unix-faq/programmer/faq/ section 1.7)
-        # and http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66012
-        
-        # Finish up with the current stdout/stderr
-        sys.stdout.flush()
-        sys.stderr.flush()
-        
-        # Do first fork.
-        try:
-            pid = os.fork()
-            if pid == 0:
-                # This is the child process. Continue.
-                pass
-            else:
-                # This is the first parent. Exit, now that we've forked.
-                self.bus.log('Forking once.')
-                os._exit(0)
-        except OSError, exc:
-            # Python raises OSError rather than returning negative numbers.
-            sys.exit("%s: fork #1 failed: (%d) %s\n"
-                     % (sys.argv[0], exc.errno, exc.strerror))
-        
-        os.setsid()
-        
-        # Do second fork
-        try:
-            pid = os.fork()
-            if pid > 0:
-                self.bus.log('Forking twice.')
-                os._exit(0) # Exit second parent
-        except OSError, exc:
-            sys.exit("%s: fork #2 failed: (%d) %s\n"
-                     % (sys.argv[0], exc.errno, exc.strerror))
-        
-        os.chdir("/")
-        os.umask(0)
-        
-        si = open(self.stdin, "r")
-        so = open(self.stdout, "a+")
-        se = open(self.stderr, "a+")
-
-        # os.dup2(fd, fd2) will close fd2 if necessary,
-        # so we don't explicitly close stdin/out/err.
-        # See http://docs.python.org/lib/os-fd-ops.html
-        os.dup2(si.fileno(), sys.stdin.fileno())
-        os.dup2(so.fileno(), sys.stdout.fileno())
-        os.dup2(se.fileno(), sys.stderr.fileno())
-        
-        self.bus.log('Daemonized to PID: %s' % os.getpid())
-        self.finalized = True
-    start.priority = 65
-
-
-class PIDFile(SimplePlugin):
-    """Maintain a PID file via a WSPBus."""
-    
-    def __init__(self, bus, pidfile):
-        SimplePlugin.__init__(self, bus)
-        self.pidfile = pidfile
-        self.finalized = False
-    
-    def start(self):
-        pid = os.getpid()
-        if self.finalized:
-            self.bus.log('PID %r already written to %r.' % (pid, self.pidfile))
-        else:
-            open(self.pidfile, "wb").write(str(pid))
-            self.bus.log('PID %r written to %r.' % (pid, self.pidfile))
-            self.finalized = True
-    start.priority = 70
-    
-    def exit(self):
-        try:
-            os.remove(self.pidfile)
-            self.bus.log('PID file removed: %r.' % self.pidfile)
-        except (KeyboardInterrupt, SystemExit):
-            raise
-        except:
-            pass
-
-
-class PerpetualTimer(threading._Timer):
-    """A subclass of threading._Timer whose run() method repeats."""
-    
-    def run(self):
-        while True:
-            self.finished.wait(self.interval)
-            if self.finished.isSet():
-                return
-            try:
-                self.function(*self.args, **self.kwargs)
-            except Exception, x:
-                self.bus.log("Error in perpetual timer thread function %r." %
-                             self.function, level=40, traceback=True)
-                # Quit on first error to avoid massive logs.
-                raise
-
-
-class Monitor(SimplePlugin):
-    """WSPBus listener to periodically run a callback in its own thread.
-    
-    bus: a Web Site Process Bus object.
-    callback: the function to call at intervals.
-    frequency: the time in seconds between callback runs.
-    """
-    
-    frequency = 60
-    
-    def __init__(self, bus, callback, frequency=60, name=None):
-        SimplePlugin.__init__(self, bus)
-        self.callback = callback
-        self.frequency = frequency
-        self.thread = None
-        self.name = name
-    
-    def start(self):
-        """Start our callback in its own perpetual timer thread."""
-        if self.frequency > 0:
-            threadname = self.name or self.__class__.__name__
-            if self.thread is None:
-                self.thread = PerpetualTimer(self.frequency, self.callback)
-                self.thread.bus = self.bus
-                self.thread.setName(threadname)
-                self.thread.start()
-                self.bus.log("Started monitor thread %r." % threadname)
-            else:
-                self.bus.log("Monitor thread %r already started." % threadname)
-    start.priority = 70
-    
-    def stop(self):
-        """Stop our callback's perpetual timer thread."""
-        if self.thread is None:
-            self.bus.log("No thread running for %s." % self.name or self.__class__.__name__)
-        else:
-            if self.thread is not threading.currentThread():
-                name = self.thread.getName()
-                self.thread.cancel()
-                self.thread.join()
-                self.bus.log("Stopped thread %r." % name)
-            self.thread = None
-    
-    def graceful(self):
-        """Stop the callback's perpetual timer thread and restart it."""
-        self.stop()
-        self.start()
-
-
-class Autoreloader(Monitor):
-    """Monitor which re-executes the process when files change."""
-    
-    frequency = 1
-    match = '.*'
-    
-    def __init__(self, bus, frequency=1, match='.*'):
-        self.mtimes = {}
-        self.files = set()
-        self.match = match
-        Monitor.__init__(self, bus, self.run, frequency)
-    
-    def start(self):
-        """Start our own perpetual timer thread for self.run."""
-        if self.thread is None:
-            self.mtimes = {}
-        Monitor.start(self)
-    start.priority = 70 
-    
-    def sysfiles(self):
-        """Return a Set of filenames which the Autoreloader will monitor."""
-        files = set()
-        for k, m in sys.modules.items():
-            if re.match(self.match, k):
-                if hasattr(m, '__loader__') and hasattr(m.__loader__, 'archive'):
-                    f = m.__loader__.archive
-                else:
-                    f = getattr(m, '__file__', None)
-                    if f is not None and not os.path.isabs(f):
-                        # ensure absolute paths so a os.chdir() in the app doesn't break me
-                        f = os.path.normpath(os.path.join(_module__file__base, f))
-                files.add(f)
-        return files
-    
-    def run(self):
-        """Reload the process if registered files have been modified."""
-        for filename in self.sysfiles() | self.files:
-            if filename:
-                if filename.endswith('.pyc'):
-                    filename = filename[:-1]
-                
-                oldtime = self.mtimes.get(filename, 0)
-                if oldtime is None:
-                    # Module with no .py file. Skip it.
-                    continue
-                
-                try:
-                    mtime = os.stat(filename).st_mtime
-                except OSError:
-                    # Either a module with no .py file, or it's been deleted.
-                    mtime = None
-                
-                if filename not in self.mtimes:
-                    # If a module has no .py file, this will be None.
-                    self.mtimes[filename] = mtime
-                else:
-                    if mtime is None or mtime > oldtime:
-                        # The file has been deleted or modified.
-                        self.bus.log("Restarting because %s changed." % filename)
-                        self.thread.cancel()
-                        self.bus.log("Stopped thread %r." % self.thread.getName())
-                        self.bus.restart()
-                        return
-
-
-class ThreadManager(SimplePlugin):
-    """Manager for HTTP request threads.
-    
-    If you have control over thread creation and destruction, publish to
-    the 'acquire_thread' and 'release_thread' channels (for each thread).
-    This will register/unregister the current thread and publish to
-    'start_thread' and 'stop_thread' listeners in the bus as needed.
-    
-    If threads are created and destroyed by code you do not control
-    (e.g., Apache), then, at the beginning of every HTTP request,
-    publish to 'acquire_thread' only. You should not publish to
-    'release_thread' in this case, since you do not know whether
-    the thread will be re-used or not. The bus will call
-    'stop_thread' listeners for you when it stops.
-    """
-    
-    def __init__(self, bus):
-        self.threads = {}
-        SimplePlugin.__init__(self, bus)
-        self.bus.listeners.setdefault('acquire_thread', set())
-        self.bus.listeners.setdefault('release_thread', set())
-    
-    def acquire_thread(self):
-        """Run 'start_thread' listeners for the current thread.
-        
-        If the current thread has already been seen, any 'start_thread'
-        listeners will not be run again.
-        """
-        thread_ident = thread.get_ident()
-        if thread_ident not in self.threads:
-            # We can't just use _get_ident as the thread ID
-            # because some platforms reuse thread ID's.
-            i = len(self.threads) + 1
-            self.threads[thread_ident] = i
-            self.bus.publish('start_thread', i)
-    
-    def release_thread(self):
-        """Release the current thread and run 'stop_thread' listeners."""
-        thread_ident = threading._get_ident()
-        i = self.threads.pop(thread_ident, None)
-        if i is not None:
-            self.bus.publish('stop_thread', i)
-    
-    def stop(self):
-        """Release all threads and run all 'stop_thread' listeners."""
-        for thread_ident, i in self.threads.items():
-            self.bus.publish('stop_thread', i)
-        self.threads.clear()
-    graceful = stop
-
--- a/bundled/cherrypy/cherrypy/process/servers.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,283 +0,0 @@
-"""Adapt an HTTP server."""
-
-import time
-
-
-class ServerAdapter(object):
-    """Adapter for an HTTP server.
-    
-    If you need to start more than one HTTP server (to serve on multiple
-    ports, or protocols, etc.), you can manually register each one and then
-    start them all with bus.start:
-    
-        s1 = ServerAdapter(bus, MyWSGIServer(host='0.0.0.0', port=80))
-        s2 = ServerAdapter(bus, another.HTTPServer(host='127.0.0.1', SSL=True))
-        s1.subscribe()
-        s2.subscribe()
-        bus.start()
-    """
-    
-    def __init__(self, bus, httpserver=None, bind_addr=None):
-        self.bus = bus
-        self.httpserver = httpserver
-        self.bind_addr = bind_addr
-        self.interrupt = None
-        self.running = False
-    
-    def subscribe(self):
-        self.bus.subscribe('start', self.start)
-        self.bus.subscribe('stop', self.stop)
-    
-    def unsubscribe(self):
-        self.bus.unsubscribe('start', self.start)
-        self.bus.unsubscribe('stop', self.stop)
-    
-    def start(self):
-        """Start the HTTP server."""
-        if self.bind_addr is None:
-            on_what = "unknown interface (dynamic?)"
-        elif isinstance(self.bind_addr, tuple):
-            host, port = self.bind_addr
-            on_what = "%s:%s" % (host, port)
-        else:
-            on_what = "socket file: %s" % self.bind_addr
-        
-        if self.running:
-            self.bus.log("Already serving on %s" % on_what)
-            return
-        
-        self.interrupt = None
-        if not self.httpserver:
-            raise ValueError("No HTTP server has been created.")
-        
-        # Start the httpserver in a new thread.
-        if isinstance(self.bind_addr, tuple):
-            wait_for_free_port(*self.bind_addr)
-        
-        import threading
-        t = threading.Thread(target=self._start_http_thread)
-        t.setName("HTTPServer " + t.getName())
-        t.start()
-        
-        self.wait()
-        self.running = True
-        self.bus.log("Serving on %s" % on_what)
-    start.priority = 75
-    
-    def _start_http_thread(self):
-        """HTTP servers MUST be running in new threads, so that the
-        main thread persists to receive KeyboardInterrupt's. If an
-        exception is raised in the httpserver's thread then it's
-        trapped here, and the bus (and therefore our httpserver)
-        are shut down.
-        """
-        try:
-            self.httpserver.start()
-        except KeyboardInterrupt, exc:
-            self.bus.log("<Ctrl-C> hit: shutting down HTTP server")
-            self.interrupt = exc
-            self.bus.exit()
-        except SystemExit, exc:
-            self.bus.log("SystemExit raised: shutting down HTTP server")
-            self.interrupt = exc
-            self.bus.exit()
-            raise
-        except:
-            import sys
-            self.interrupt = sys.exc_info()[1]
-            self.bus.log("Error in HTTP server: shutting down",
-                         traceback=True, level=40)
-            self.bus.exit()
-            raise
-    
-    def wait(self):
-        """Wait until the HTTP server is ready to receive requests."""
-        while not getattr(self.httpserver, "ready", False):
-            if self.interrupt:
-                raise self.interrupt
-            time.sleep(.1)
-        
-        # Wait for port to be occupied
-        if isinstance(self.bind_addr, tuple):
-            host, port = self.bind_addr
-            wait_for_occupied_port(host, port)
-    
-    def stop(self):
-        """Stop the HTTP server."""
-        if self.running:
-            # stop() MUST block until the server is *truly* stopped.
-            self.httpserver.stop()
-            # Wait for the socket to be truly freed.
-            if isinstance(self.bind_addr, tuple):
-                wait_for_free_port(*self.bind_addr)
-            self.running = False
-            self.bus.log("HTTP Server %s shut down" % self.httpserver)
-        else:
-            self.bus.log("HTTP Server %s already shut down" % self.httpserver)
-    stop.priority = 25
-    
-    def restart(self):
-        """Restart the HTTP server."""
-        self.stop()
-        self.start()
-
-
-class FlupFCGIServer(object):
-    """Adapter for a flup.server.fcgi.WSGIServer."""
-    
-    def __init__(self, *args, **kwargs):
-        if kwargs.get('bindAddress', None) is None:
-            import socket
-            if not hasattr(socket.socket, 'fromfd'):
-                raise ValueError(
-                    'Dynamic FCGI server not available on this platform. '
-                    'You must use a static or external one by providing a '
-                    'legal bindAddress.')
-        self.args = args
-        self.kwargs = kwargs
-        self.ready = False
-    
-    def start(self):
-        """Start the FCGI server."""
-        # We have to instantiate the server class here because its __init__
-        # starts a threadpool. If we do it too early, daemonize won't work.
-        from flup.server.fcgi import WSGIServer
-        self.fcgiserver = WSGIServer(*self.args, **self.kwargs)
-        # TODO: report this bug upstream to flup.
-        # If we don't set _oldSIGs on Windows, we get:
-        #   File "C:\Python24\Lib\site-packages\flup\server\threadedserver.py",
-        #   line 108, in run
-        #     self._restoreSignalHandlers()
-        #   File "C:\Python24\Lib\site-packages\flup\server\threadedserver.py",
-        #   line 156, in _restoreSignalHandlers
-        #     for signum,handler in self._oldSIGs:
-        #   AttributeError: 'WSGIServer' object has no attribute '_oldSIGs'
-        self.fcgiserver._installSignalHandlers = lambda: None
-        self.fcgiserver._oldSIGs = []
-        self.ready = True
-        self.fcgiserver.run()
-    
-    def stop(self):
-        """Stop the HTTP server."""
-        # Forcibly stop the fcgi server main event loop.
-        self.fcgiserver._keepGoing = False
-        # Force all worker threads to die off.
-        self.fcgiserver._threadPool.maxSpare = self.fcgiserver._threadPool._idleCount
-        self.ready = False
-
-
-class FlupSCGIServer(object):
-    """Adapter for a flup.server.scgi.WSGIServer."""
-    
-    def __init__(self, *args, **kwargs):
-        self.args = args
-        self.kwargs = kwargs
-        self.ready = False
-    
-    def start(self):
-        """Start the SCGI server."""
-        # We have to instantiate the server class here because its __init__
-        # starts a threadpool. If we do it too early, daemonize won't work.
-        from flup.server.scgi import WSGIServer
-        self.scgiserver = WSGIServer(*self.args, **self.kwargs)
-        # TODO: report this bug upstream to flup.
-        # If we don't set _oldSIGs on Windows, we get:
-        #   File "C:\Python24\Lib\site-packages\flup\server\threadedserver.py",
-        #   line 108, in run
-        #     self._restoreSignalHandlers()
-        #   File "C:\Python24\Lib\site-packages\flup\server\threadedserver.py",
-        #   line 156, in _restoreSignalHandlers
-        #     for signum,handler in self._oldSIGs:
-        #   AttributeError: 'WSGIServer' object has no attribute '_oldSIGs'
-        self.scgiserver._installSignalHandlers = lambda: None
-        self.scgiserver._oldSIGs = []
-        self.ready = True
-        self.scgiserver.run()
-    
-    def stop(self):
-        """Stop the HTTP server."""
-        self.ready = False
-        # Forcibly stop the scgi server main event loop.
-        self.scgiserver._keepGoing = False
-        # Force all worker threads to die off.
-        self.scgiserver._threadPool.maxSpare = 0
-
-
-def client_host(server_host):
-    """Return the host on which a client can connect to the given listener."""
-    if server_host == '0.0.0.0':
-        # 0.0.0.0 is INADDR_ANY, which should answer on localhost.
-        return '127.0.0.1'
-    if server_host == '::':
-        # :: is IN6ADDR_ANY, which should answer on localhost.
-        return '::1'
-    return server_host
-
-def check_port(host, port, timeout=1.0):
-    """Raise an error if the given port is not free on the given host."""
-    if not host:
-        raise ValueError("Host values of '' or None are not allowed.")
-    host = client_host(host)
-    port = int(port)
-    
-    import socket
-    
-    # AF_INET or AF_INET6 socket
-    # Get the correct address family for our host (allows IPv6 addresses)
-    try:
-        info = socket.getaddrinfo(host, port, socket.AF_UNSPEC,
-                                  socket.SOCK_STREAM)
-    except socket.gaierror:
-        if ':' in host:
-            info = [(socket.AF_INET6, socket.SOCK_STREAM, 0, "", (host, port, 0, 0))]
-        else:
-            info = [(socket.AF_INET, socket.SOCK_STREAM, 0, "", (host, port))]
-    
-    for res in info:
-        af, socktype, proto, canonname, sa = res
-        s = None
-        try:
-            s = socket.socket(af, socktype, proto)
-            # See http://groups.google.com/group/cherrypy-users/
-            #        browse_frm/thread/bbfe5eb39c904fe0
-            s.settimeout(timeout)
-            s.connect((host, port))
-            s.close()
-            raise IOError("Port %s is in use on %s; perhaps the previous "
-                          "httpserver did not shut down properly." %
-                          (repr(port), repr(host)))
-        except socket.error:
-            if s:
-                s.close()
-
-def wait_for_free_port(host, port):
-    """Wait for the specified port to become free (drop requests)."""
-    if not host:
-        raise ValueError("Host values of '' or None are not allowed.")
-    
-    for trial in range(50):
-        try:
-            # we are expecting a free port, so reduce the timeout
-            check_port(host, port, timeout=0.1)
-        except IOError:
-            # Give the old server thread time to free the port.
-            time.sleep(0.1)
-        else:
-            return
-    
-    raise IOError("Port %r not free on %r" % (port, host))
-
-def wait_for_occupied_port(host, port):
-    """Wait for the specified port to become active (receive requests)."""
-    if not host:
-        raise ValueError("Host values of '' or None are not allowed.")
-    
-    for trial in range(50):
-        try:
-            check_port(host, port)
-        except IOError:
-            return
-        else:
-            time.sleep(.1)
-    
-    raise IOError("Port %r not bound on %r" % (port, host))
--- a/bundled/cherrypy/cherrypy/process/win32.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,174 +0,0 @@
-"""Windows service. Requires pywin32."""
-
-import os
-import win32api
-import win32con
-import win32event
-import win32service
-import win32serviceutil
-
-from cherrypy.process import wspbus, plugins
-
-
-class ConsoleCtrlHandler(plugins.SimplePlugin):
-    """A WSPBus plugin for handling Win32 console events (like Ctrl-C)."""
-    
-    def __init__(self, bus):
-        self.is_set = False
-        plugins.SimplePlugin.__init__(self, bus)
-    
-    def start(self):
-        if self.is_set:
-            self.bus.log('Handler for console events already set.', level=40)
-            return
-        
-        result = win32api.SetConsoleCtrlHandler(self.handle, 1)
-        if result == 0:
-            self.bus.log('Could not SetConsoleCtrlHandler (error %r)' %
-                         win32api.GetLastError(), level=40)
-        else:
-            self.bus.log('Set handler for console events.', level=40)
-            self.is_set = True
-    
-    def stop(self):
-        if not self.is_set:
-            self.bus.log('Handler for console events already off.', level=40)
-            return
-        
-        try:
-            result = win32api.SetConsoleCtrlHandler(self.handle, 0)
-        except ValueError:
-            # "ValueError: The object has not been registered"
-            result = 1
-        
-        if result == 0:
-            self.bus.log('Could not remove SetConsoleCtrlHandler (error %r)' %
-                         win32api.GetLastError(), level=40)
-        else:
-            self.bus.log('Removed handler for console events.', level=40)
-            self.is_set = False
-    
-    def handle(self, event):
-        """Handle console control events (like Ctrl-C)."""
-        if event in (win32con.CTRL_C_EVENT, win32con.CTRL_LOGOFF_EVENT,
-                     win32con.CTRL_BREAK_EVENT, win32con.CTRL_SHUTDOWN_EVENT,
-                     win32con.CTRL_CLOSE_EVENT):
-            self.bus.log('Console event %s: shutting down bus' % event)
-            
-            # Remove self immediately so repeated Ctrl-C doesn't re-call it.
-            try:
-                self.stop()
-            except ValueError:
-                pass
-            
-            self.bus.exit()
-            # 'First to return True stops the calls'
-            return 1
-        return 0
-
-
-class Win32Bus(wspbus.Bus):
-    """A Web Site Process Bus implementation for Win32.
-    
-    Instead of time.sleep, this bus blocks using native win32event objects.
-    """
-    
-    def __init__(self):
-        self.events = {}
-        wspbus.Bus.__init__(self)
-    
-    def _get_state_event(self, state):
-        """Return a win32event for the given state (creating it if needed)."""
-        try:
-            return self.events[state]
-        except KeyError:
-            event = win32event.CreateEvent(None, 0, 0,
-                                           "WSPBus %s Event (pid=%r)" %
-                                           (state.name, os.getpid()))
-            self.events[state] = event
-            return event
-    
-    def _get_state(self):
-        return self._state
-    def _set_state(self, value):
-        self._state = value
-        event = self._get_state_event(value)
-        win32event.PulseEvent(event)
-    state = property(_get_state, _set_state)
-    
-    def wait(self, state, interval=0.1, channel=None):
-        """Wait for the given state(s), KeyboardInterrupt or SystemExit.
-        
-        Since this class uses native win32event objects, the interval
-        argument is ignored.
-        """
-        if isinstance(state, (tuple, list)):
-            # Don't wait for an event that beat us to the punch ;)
-            if self.state not in state:
-                events = tuple([self._get_state_event(s) for s in state])
-                win32event.WaitForMultipleObjects(events, 0, win32event.INFINITE)
-        else:
-            # Don't wait for an event that beat us to the punch ;)
-            if self.state != state:
-                event = self._get_state_event(state)
-                win32event.WaitForSingleObject(event, win32event.INFINITE)
-
-
-class _ControlCodes(dict):
-    """Control codes used to "signal" a service via ControlService.
-    
-    User-defined control codes are in the range 128-255. We generally use
-    the standard Python value for the Linux signal and add 128. Example:
-    
-        >>> signal.SIGUSR1
-        10
-        control_codes['graceful'] = 128 + 10
-    """
-    
-    def key_for(self, obj):
-        """For the given value, return its corresponding key."""
-        for key, val in self.items():
-            if val is obj:
-                return key
-        raise ValueError("The given object could not be found: %r" % obj)
-
-control_codes = _ControlCodes({'graceful': 138})
-
-
-def signal_child(service, command):
-    if command == 'stop':
-        win32serviceutil.StopService(service)
-    elif command == 'restart':
-        win32serviceutil.RestartService(service)
-    else:
-        win32serviceutil.ControlService(service, control_codes[command])
-
-
-class PyWebService(win32serviceutil.ServiceFramework):
-    """Python Web Service."""
-    
-    _svc_name_ = "Python Web Service"
-    _svc_display_name_ = "Python Web Service"
-    _svc_deps_ = None        # sequence of service names on which this depends
-    _exe_name_ = "pywebsvc"
-    _exe_args_ = None        # Default to no arguments
-    
-    # Only exists on Windows 2000 or later, ignored on windows NT
-    _svc_description_ = "Python Web Service"
-    
-    def SvcDoRun(self):
-        from cherrypy import process
-        process.bus.start()
-        process.bus.block()
-    
-    def SvcStop(self):
-        from cherrypy import process
-        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
-        process.bus.exit()
-    
-    def SvcOther(self, control):
-        process.bus.publish(control_codes.key_for(control))
-
-
-if __name__ == '__main__':
-    win32serviceutil.HandleCommandLine(PyWebService)
--- a/bundled/cherrypy/cherrypy/process/wspbus.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,384 +0,0 @@
-"""An implementation of the Web Site Process Bus.
-
-This module is completely standalone, depending only on the stdlib.
-
-Web Site Process Bus
---------------------
-
-A Bus object is used to contain and manage site-wide behavior:
-daemonization, HTTP server start/stop, process reload, signal handling,
-drop privileges, PID file management, logging for all of these,
-and many more.
-
-In addition, a Bus object provides a place for each web framework
-to register code that runs in response to site-wide events (like
-process start and stop), or which controls or otherwise interacts with
-the site-wide components mentioned above. For example, a framework which
-uses file-based templates would add known template filenames to an
-autoreload component.
-
-Ideally, a Bus object will be flexible enough to be useful in a variety
-of invocation scenarios:
-
- 1. The deployer starts a site from the command line via a framework-
-     neutral deployment script; applications from multiple frameworks
-     are mixed in a single site. Command-line arguments and configuration
-     files are used to define site-wide components such as the HTTP server,
-     WSGI component graph, autoreload behavior, signal handling, etc.
- 2. The deployer starts a site via some other process, such as Apache;
-     applications from multiple frameworks are mixed in a single site.
-     Autoreload and signal handling (from Python at least) are disabled.
- 3. The deployer starts a site via a framework-specific mechanism;
-     for example, when running tests, exploring tutorials, or deploying
-     single applications from a single framework. The framework controls
-     which site-wide components are enabled as it sees fit.
-
-The Bus object in this package uses topic-based publish-subscribe
-messaging to accomplish all this. A few topic channels are built in
-('start', 'stop', 'exit', 'graceful', 'log', and 'main'). Frameworks and
-site containers are free to define their own. If a message is sent to a
-channel that has not been defined or has no listeners, there is no effect.
-
-In general, there should only ever be a single Bus object per process.
-Frameworks and site containers share a single Bus object by publishing
-messages and subscribing listeners.
-
-The Bus object works as a finite state machine which models the current
-state of the process. Bus methods move it from one state to another;
-those methods then publish to subscribed listeners on the channel for
-the new state.
-
-                        O
-                        |
-                        V
-       STOPPING --> STOPPED --> EXITING -> X
-          A   A         |
-          |    \___     |
-          |        \    |
-          |         V   V
-        STARTED <-- STARTING
-
-"""
-
-import atexit
-import os
-try:
-    set
-except NameError:
-    from sets import Set as set
-import sys
-import threading
-import time
-import traceback as _traceback
-import warnings
-
-# Here I save the value of os.getcwd(), which, if I am imported early enough,
-# will be the directory from which the startup script was run.  This is needed
-# by _do_execv(), to change back to the original directory before execv()ing a
-# new process.  This is a defense against the application having changed the
-# current working directory (which could make sys.executable "not found" if
-# sys.executable is a relative-path, and/or cause other problems).
-_startup_cwd = os.getcwd()
-
-class ChannelFailures(Exception):
-    delimiter = '\n'
-    
-    def __init__(self, *args, **kwargs):
-        # Don't use 'super' here; Exceptions are old-style in Py2.4
-        # See http://www.cherrypy.org/ticket/959
-        Exception.__init__(self, *args, **kwargs)
-        self._exceptions = list()
-    
-    def handle_exception(self):
-        self._exceptions.append(sys.exc_info())
-    
-    def get_instances(self):
-        return [instance for cls, instance, traceback in self._exceptions]
-    
-    def __str__(self):
-        exception_strings = map(repr, self.get_instances())
-        return self.delimiter.join(exception_strings)
-    
-    def __nonzero__(self):
-        return bool(self._exceptions)
-
-# Use a flag to indicate the state of the bus.
-class _StateEnum(object):
-    class State(object):
-        name = None
-        def __repr__(self):
-            return "states.%s" % self.name
-    
-    def __setattr__(self, key, value):
-        if isinstance(value, self.State):
-            value.name = key
-        object.__setattr__(self, key, value)
-states = _StateEnum()
-states.STOPPED = states.State()
-states.STARTING = states.State()
-states.STARTED = states.State()
-states.STOPPING = states.State()
-states.EXITING = states.State()
-
-
-class Bus(object):
-    """Process state-machine and messenger for HTTP site deployment.
-    
-    All listeners for a given channel are guaranteed to be called even
-    if others at the same channel fail. Each failure is logged, but
-    execution proceeds on to the next listener. The only way to stop all
-    processing from inside a listener is to raise SystemExit and stop the
-    whole server.
-    """
-    
-    states = states
-    state = states.STOPPED
-    execv = False
-    
-    def __init__(self):
-        self.execv = False
-        self.state = states.STOPPED
-        self.listeners = dict(
-            [(channel, set()) for channel
-             in ('start', 'stop', 'exit', 'graceful', 'log', 'main')])
-        self._priorities = {}
-    
-    def subscribe(self, channel, callback, priority=None):
-        """Add the given callback at the given channel (if not present)."""
-        if channel not in self.listeners:
-            self.listeners[channel] = set()
-        self.listeners[channel].add(callback)
-        
-        if priority is None:
-            priority = getattr(callback, 'priority', 50)
-        self._priorities[(channel, callback)] = priority
-    
-    def unsubscribe(self, channel, callback):
-        """Discard the given callback (if present)."""
-        listeners = self.listeners.get(channel)
-        if listeners and callback in listeners:
-            listeners.discard(callback)
-            del self._priorities[(channel, callback)]
-    
-    def publish(self, channel, *args, **kwargs):
-        """Return output of all subscribers for the given channel."""
-        if channel not in self.listeners:
-            return []
-        
-        exc = ChannelFailures()
-        output = []
-        
-        items = [(self._priorities[(channel, listener)], listener)
-                 for listener in self.listeners[channel]]
-        items.sort()
-        for priority, listener in items:
-            try:
-                output.append(listener(*args, **kwargs))
-            except KeyboardInterrupt:
-                raise
-            except SystemExit, e:
-                # If we have previous errors ensure the exit code is non-zero
-                if exc and e.code == 0:
-                    e.code = 1
-                raise
-            except:
-                exc.handle_exception()
-                if channel == 'log':
-                    # Assume any further messages to 'log' will fail.
-                    pass
-                else:
-                    self.log("Error in %r listener %r" % (channel, listener),
-                             level=40, traceback=True)
-        if exc:
-            raise exc
-        return output
-    
-    def _clean_exit(self):
-        """An atexit handler which asserts the Bus is not running."""
-        if self.state != states.EXITING:
-            warnings.warn(
-                "The main thread is exiting, but the Bus is in the %r state; "
-                "shutting it down automatically now. You must either call "
-                "bus.block() after start(), or call bus.exit() before the "
-                "main thread exits." % self.state, RuntimeWarning)
-            self.exit()
-    
-    def start(self):
-        """Start all services."""
-        atexit.register(self._clean_exit)
-        
-        self.state = states.STARTING
-        self.log('Bus STARTING')
-        try:
-            self.publish('start')
-            self.state = states.STARTED
-            self.log('Bus STARTED')
-        except (KeyboardInterrupt, SystemExit):
-            raise
-        except:
-            self.log("Shutting down due to error in start listener:",
-                     level=40, traceback=True)
-            e_info = sys.exc_info()
-            try:
-                self.exit()
-            except:
-                # Any stop/exit errors will be logged inside publish().
-                pass
-            raise e_info[0], e_info[1], e_info[2]
-    
-    def exit(self):
-        """Stop all services and prepare to exit the process."""
-        exitstate = self.state
-        try:
-            self.stop()
-            
-            self.state = states.EXITING
-            self.log('Bus EXITING')
-            self.publish('exit')
-            # This isn't strictly necessary, but it's better than seeing
-            # "Waiting for child threads to terminate..." and then nothing.
-            self.log('Bus EXITED')
-        except:
-            # This method is often called asynchronously (whether thread,
-            # signal handler, console handler, or atexit handler), so we
-            # can't just let exceptions propagate out unhandled.
-            # Assume it's been logged and just die.
-            os._exit(70) # EX_SOFTWARE
-        
-        if exitstate == states.STARTING:
-            # exit() was called before start() finished, possibly due to
-            # Ctrl-C because a start listener got stuck. In this case,
-            # we could get stuck in a loop where Ctrl-C never exits the
-            # process, so we just call os.exit here.
-            os._exit(70) # EX_SOFTWARE
-    
-    def restart(self):
-        """Restart the process (may close connections).
-        
-        This method does not restart the process from the calling thread;
-        instead, it stops the bus and asks the main thread to call execv.
-        """
-        self.execv = True
-        self.exit()
-    
-    def graceful(self):
-        """Advise all services to reload."""
-        self.log('Bus graceful')
-        self.publish('graceful')
-    
-    def block(self, interval=0.1):
-        """Wait for the EXITING state, KeyboardInterrupt or SystemExit.
-        
-        This function is intended to be called only by the main thread.
-        After waiting for the EXITING state, it also waits for all threads
-        to terminate, and then calls os.execv if self.execv is True. This
-        design allows another thread to call bus.restart, yet have the main
-        thread perform the actual execv call (required on some platforms).
-        """
-        try:
-            self.wait(states.EXITING, interval=interval, channel='main')
-        except (KeyboardInterrupt, IOError):
-            # The time.sleep call might raise
-            # "IOError: [Errno 4] Interrupted function call" on KBInt.
-            self.log('Keyboard Interrupt: shutting down bus')
-            self.exit()
-        except SystemExit:
-            self.log('SystemExit raised: shutting down bus')
-            self.exit()
-            raise
-        
-        # Waiting for ALL child threads to finish is necessary on OS X.
-        # See http://www.cherrypy.org/ticket/581.
-        # It's also good to let them all shut down before allowing
-        # the main thread to call atexit handlers.
-        # See http://www.cherrypy.org/ticket/751.
-        self.log("Waiting for child threads to terminate...")
-        for t in threading.enumerate():
-            if t != threading.currentThread() and t.isAlive():
-                # Note that any dummy (external) threads are always daemonic.
-                if hasattr(threading.Thread, "daemon"):
-                    # Python 2.6+
-                    d = t.daemon
-                else:
-                    d = t.isDaemon()
-                if not d:
-                    t.join()
-        
-        if self.execv:
-            self._do_execv()
-    
-    def wait(self, state, interval=0.1, channel=None):
-        """Wait for the given state(s)."""
-        if isinstance(state, (tuple, list)):
-            states = state
-        else:
-            states = [state]
-        
-        def _wait():
-            while self.state not in states:
-                time.sleep(interval)
-                self.publish(channel)
-        
-        # From http://psyco.sourceforge.net/psycoguide/bugs.html:
-        # "The compiled machine code does not include the regular polling
-        # done by Python, meaning that a KeyboardInterrupt will not be
-        # detected before execution comes back to the regular Python
-        # interpreter. Your program cannot be interrupted if caught
-        # into an infinite Psyco-compiled loop."
-        try:
-            sys.modules['psyco'].cannotcompile(_wait)
-        except (KeyError, AttributeError):
-            pass
-        
-        _wait()
-    
-    def _do_execv(self):
-        """Re-execute the current process.
-        
-        This must be called from the main thread, because certain platforms
-        (OS X) don't allow execv to be called in a child thread very well.
-        """
-        args = sys.argv[:]
-        self.log('Re-spawning %s' % ' '.join(args))
-        args.insert(0, sys.executable)
-        if sys.platform == 'win32':
-            args = ['"%s"' % arg for arg in args]
-
-        os.chdir(_startup_cwd)
-        os.execv(sys.executable, args)
-    
-    def stop(self):
-        """Stop all services."""
-        self.state = states.STOPPING
-        self.log('Bus STOPPING')
-        self.publish('stop')
-        self.state = states.STOPPED
-        self.log('Bus STOPPED')
-    
-    def start_with_callback(self, func, args=None, kwargs=None):
-        """Start 'func' in a new thread T, then start self (and return T)."""
-        if args is None:
-            args = ()
-        if kwargs is None:
-            kwargs = {}
-        args = (func,) + args
-        
-        def _callback(func, *a, **kw):
-            self.wait(states.STARTED)
-            func(*a, **kw)
-        t = threading.Thread(target=_callback, args=args, kwargs=kwargs)
-        t.setName('Bus Callback ' + t.getName())
-        t.start()
-        
-        self.start()
-        
-        return t
-    
-    def log(self, msg="", level=20, traceback=False):
-        """Log the given message. Append the last traceback if requested."""
-        if traceback:
-            exc = sys.exc_info()
-            msg += "\n" + "".join(_traceback.format_exception(*exc))
-        self.publish('log', msg, level)
-
-bus = Bus()
--- a/bundled/cherrypy/cherrypy/scaffold/__init__.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
-"""<MyProject>, a CherryPy application.
-
-Use this as a base for creating new CherryPy applications. When you want
-to make a new app, copy and paste this folder to some other location
-(maybe site-packages) and rename it to the name of your project,
-then tweak as desired.
-
-Even before any tweaking, this should serve a few demonstration pages.
-Change to this directory and run:
-
-    ../cherryd -c site.conf
-
-"""
-
-import cherrypy
-from cherrypy import tools, url
-
-import os
-local_dir = os.path.join(os.getcwd(), os.path.dirname(__file__))
-
-
-class Root:
-    
-    _cp_config = {'tools.log_tracebacks.on': True,
-                  }
-    
-    def index(self):
-        return """<html>
-<body>Try some <a href='%s?a=7'>other</a> path,
-or a <a href='%s?n=14'>default</a> path.<br />
-Or, just look at the pretty picture:<br />
-<img src='%s' />
-</body></html>""" % (url("other"), url("else"),
-                     url("files/made_with_cherrypy_small.png"))
-    index.exposed = True
-    
-    def default(self, *args, **kwargs):
-        return "args: %s kwargs: %s" % (args, kwargs)
-    default.exposed = True
-    
-    def other(self, a=2, b='bananas', c=None):
-        cherrypy.response.headers['Content-Type'] = 'text/plain'
-        if c is None:
-            return "Have %d %s." % (int(a), b)
-        else:
-            return "Have %d %s, %s." % (int(a), b, c)
-    other.exposed = True
-    
-    files = cherrypy.tools.staticdir.handler(
-                section="/files",
-                dir=os.path.join(local_dir, "static"),
-                # Ignore .php files, etc.
-                match=r'\.(css|gif|html?|ico|jpe?g|js|png|swf|xml)$',
-                )
-
-
-root = Root()
-
-# Uncomment the following to use your own favicon instead of CP's default.
-#favicon_path = os.path.join(local_dir, "favicon.ico")
-#root.favicon_ico = tools.staticfile.handler(filename=favicon_path)
--- a/bundled/cherrypy/cherrypy/scaffold/apache-fcgi.conf	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,22 +0,0 @@
-# Apache2 server conf file for using CherryPy with mod_fcgid.
-
-# This doesn't have to be "C:/", but it has to be a directory somewhere, and
-# MUST match the directory used in the FastCgiExternalServer directive, below.
-DocumentRoot "C:/"
-
-ServerName 127.0.0.1
-Listen 80
-LoadModule fastcgi_module modules/mod_fastcgi.dll
-LoadModule rewrite_module modules/mod_rewrite.so
-
-Options ExecCGI
-SetHandler fastcgi-script
-RewriteEngine On
-# Send requests for any URI to our fastcgi handler.
-RewriteRule ^(.*)$ /fastcgi.pyc [L]
-
-# The FastCgiExternalServer directive defines filename as an external FastCGI application.
-# If filename does not begin with a slash (/) then it is assumed to be relative to the ServerRoot.
-# The filename does not have to exist in the local filesystem. URIs that Apache resolves to this
-# filename will be handled by this external FastCGI application.
-FastCgiExternalServer "C:/fastcgi.pyc" -host 127.0.0.1:8088
\ No newline at end of file
--- a/bundled/cherrypy/cherrypy/scaffold/example.conf	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-[/]
-log.error_file: "error.log"
-log.access_file: "access.log"
\ No newline at end of file
--- a/bundled/cherrypy/cherrypy/scaffold/site.conf	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-[global]
-# Uncomment this when you're done developing
-#environment: "production"
-
-server.socket_host: "0.0.0.0"
-server.socket_port: 8088
-
-# Uncomment the following lines to run on HTTPS at the same time
-#server.2.socket_host: "0.0.0.0"
-#server.2.socket_port: 8433
-#server.2.ssl_certificate: '../test/test.pem'
-#server.2.ssl_private_key: '../test/test.pem'
-
-tree.myapp: cherrypy.Application(scaffold.root, "/", "example.conf")
Binary file bundled/cherrypy/cherrypy/scaffold/static/made_with_cherrypy_small.png has changed
--- a/bundled/cherrypy/cherrypy/test/__init__.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-"""Regression test suite for CherryPy.
-
-Run test.py to exercise all tests.
-"""
-
--- a/bundled/cherrypy/cherrypy/test/benchmark.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,408 +0,0 @@
-"""CherryPy Benchmark Tool
-
-    Usage:
-        benchmark.py --null --notests --help --cpmodpy --modpython --ab=path --apache=path
-    
-    --null:        use a null Request object (to bench the HTTP server only)
-    --notests:     start the server but do not run the tests; this allows
-                   you to check the tested pages with a browser
-    --help:        show this help message
-    --cpmodpy:     run tests via apache on 8080 (with the builtin _cpmodpy)
-    --modpython:   run tests via apache on 8080 (with modpython_gateway)
-    --ab=path:     Use the ab script/executable at 'path' (see below)
-    --apache=path: Use the apache script/exe at 'path' (see below)
-    
-    To run the benchmarks, the Apache Benchmark tool "ab" must either be on
-    your system path, or specified via the --ab=path option.
-    
-    To run the modpython tests, the "apache" executable or script must be
-    on your system path, or provided via the --apache=path option. On some
-    platforms, "apache" may be called "apachectl" or "apache2ctl"--create
-    a symlink to them if needed.
-"""
-
-import getopt
-import os
-curdir = os.path.join(os.getcwd(), os.path.dirname(__file__))
-
-import re
-import sys
-import time
-import traceback
-
-import cherrypy
-from cherrypy import _cperror, _cpmodpy
-from cherrypy.lib import httputil
-
-
-AB_PATH = ""
-APACHE_PATH = "apache"
-SCRIPT_NAME = "/cpbench/users/rdelon/apps/blog"
-
-__all__ = ['ABSession', 'Root', 'print_report',
-           'run_standard_benchmarks', 'safe_threads',
-           'size_report', 'startup', 'thread_report',
-           ]
-
-size_cache = {}
-
-class Root:
-    
-    def index(self):
-        return """<html>
-<head>
-    <title>CherryPy Benchmark</title>
-</head>
-<body>
-    <ul>
-        <li><a href="hello">Hello, world! (14 byte dynamic)</a></li>
-        <li><a href="static/index.html">Static file (14 bytes static)</a></li>
-        <li><form action="sizer">Response of length:
-            <input type='text' name='size' value='10' /></form>
-        </li>
-    </ul>
-</body>
-</html>"""
-    index.exposed = True
-    
-    def hello(self):
-        return "Hello, world\r\n"
-    hello.exposed = True
-    
-    def sizer(self, size):
-        resp = size_cache.get(size, None)
-        if resp is None:
-            size_cache[size] = resp = "X" * int(size)
-        return resp
-    sizer.exposed = True
-
-
-cherrypy.config.update({
-    'log.error.file': '',
-    'environment': 'production',
-    'server.socket_host': '127.0.0.1',
-    'server.socket_port': 8080,
-    'server.max_request_header_size': 0,
-    'server.max_request_body_size': 0,
-    'engine.deadlock_poll_freq': 0,
-    })
-
-# Cheat mode on ;)
-del cherrypy.config['tools.log_tracebacks.on']
-del cherrypy.config['tools.log_headers.on']
-del cherrypy.config['tools.trailing_slash.on']
-
-appconf = {
-    '/static': {
-        'tools.staticdir.on': True,
-        'tools.staticdir.dir': 'static',
-        'tools.staticdir.root': curdir,
-        },
-    }
-app = cherrypy.tree.mount(Root(), SCRIPT_NAME, appconf)
-
-
-class NullRequest:
-    """A null HTTP request class, returning 204 and an empty body."""
-    
-    def __init__(self, local, remote, scheme="http"):
-        pass
-    
-    def close(self):
-        pass
-    
-    def run(self, method, path, query_string, protocol, headers, rfile):
-        cherrypy.response.status = "204 No Content"
-        cherrypy.response.header_list = [("Content-Type", 'text/html'),
-                                         ("Server", "Null CherryPy"),
-                                         ("Date", httputil.HTTPDate()),
-                                         ("Content-Length", "0"),
-                                         ]
-        cherrypy.response.body = [""]
-        return cherrypy.response
-
-
-class NullResponse:
-    pass
-
-
-class ABSession:
-    """A session of 'ab', the Apache HTTP server benchmarking tool.
-
-Example output from ab:
-
-This is ApacheBench, Version 2.0.40-dev <$Revision: 1.121.2.1 $> apache-2.0
-Copyright (c) 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
-Copyright (c) 1998-2002 The Apache Software Foundation, http://www.apache.org/
-
-Benchmarking 127.0.0.1 (be patient)
-Completed 100 requests
-Completed 200 requests
-Completed 300 requests
-Completed 400 requests
-Completed 500 requests
-Completed 600 requests
-Completed 700 requests
-Completed 800 requests
-Completed 900 requests
-
-
-Server Software:        CherryPy/3.1beta
-Server Hostname:        127.0.0.1
-Server Port:            8080
-
-Document Path:          /static/index.html
-Document Length:        14 bytes
-
-Concurrency Level:      10
-Time taken for tests:   9.643867 seconds
-Complete requests:      1000
-Failed requests:        0
-Write errors:           0
-Total transferred:      189000 bytes
-HTML transferred:       14000 bytes
-Requests per second:    103.69 [#/sec] (mean)
-Time per request:       96.439 [ms] (mean)
-Time per request:       9.644 [ms] (mean, across all concurrent requests)
-Transfer rate:          19.08 [Kbytes/sec] received
-
-Connection Times (ms)
-              min  mean[+/-sd] median   max
-Connect:        0    0   2.9      0      10
-Processing:    20   94   7.3     90     130
-Waiting:        0   43  28.1     40     100
-Total:         20   95   7.3    100     130
-
-Percentage of the requests served within a certain time (ms)
-  50%    100
-  66%    100
-  75%    100
-  80%    100
-  90%    100
-  95%    100
-  98%    100
-  99%    110
- 100%    130 (longest request)
-Finished 1000 requests
-"""
-    
-    parse_patterns = [('complete_requests', 'Completed',
-                       r'^Complete requests:\s*(\d+)'),
-                      ('failed_requests', 'Failed',
-                       r'^Failed requests:\s*(\d+)'),
-                      ('requests_per_second', 'req/sec',
-                       r'^Requests per second:\s*([0-9.]+)'),
-                      ('time_per_request_concurrent', 'msec/req',
-                       r'^Time per request:\s*([0-9.]+).*concurrent requests\)$'),
-                      ('transfer_rate', 'KB/sec',
-                       r'^Transfer rate:\s*([0-9.]+)'),
-                      ]
-    
-    def __init__(self, path=SCRIPT_NAME + "/hello", requests=1000, concurrency=10):
-        self.path = path
-        self.requests = requests
-        self.concurrency = concurrency
-    
-    def args(self):
-        port = cherrypy.server.socket_port
-        assert self.concurrency > 0
-        assert self.requests > 0
-        # Don't use "localhost".
-        # Cf http://mail.python.org/pipermail/python-win32/2008-March/007050.html
-        return ("-k -n %s -c %s http://127.0.0.1:%s%s" %
-                (self.requests, self.concurrency, port, self.path))
-    
-    def run(self):
-        # Parse output of ab, setting attributes on self
-        try:
-            self.output = _cpmodpy.read_process(AB_PATH or "ab", self.args())
-        except:
-            print _cperror.format_exc()
-            raise
-        
-        for attr, name, pattern in self.parse_patterns:
-            val = re.search(pattern, self.output, re.MULTILINE)
-            if val:
-                val = val.group(1)
-                setattr(self, attr, val)
-            else:
-                setattr(self, attr, None)
-
-
-safe_threads = (25, 50, 100, 200, 400)
-if sys.platform in ("win32",):
-    # For some reason, ab crashes with > 50 threads on my Win2k laptop.
-    safe_threads = (10, 20, 30, 40, 50)
-
-
-def thread_report(path=SCRIPT_NAME + "/hello", concurrency=safe_threads):
-    sess = ABSession(path)
-    attrs, names, patterns = list(zip(*sess.parse_patterns))
-    avg = dict.fromkeys(attrs, 0.0)
-    
-    rows = [('threads',) + names]
-    for c in concurrency:
-        sess.concurrency = c
-        sess.run()
-        row = [c]
-        for attr in attrs:
-            val = float(getattr(sess, attr))
-            avg[attr] += float(val)
-            row.append(val)
-        rows.append(row)
-    
-    # Add a row of averages.
-    rows.append(["Average"] + [str(avg[attr] / len(concurrency)) for attr in attrs])
-    return rows
-
-def size_report(sizes=(10, 100, 1000, 10000, 100000, 100000000),
-               concurrency=50):
-    sess = ABSession(concurrency=concurrency)
-    attrs, names, patterns = list(zip(*sess.parse_patterns))
-    rows = [('bytes',) + names]
-    for sz in sizes:
-        sess.path = "%s/sizer?size=%s" % (SCRIPT_NAME, sz)
-        sess.run()
-        rows.append([sz] + [getattr(sess, attr) for attr in attrs])
-    return rows
-
-def print_report(rows):
-    widths = []
-    for i in range(len(rows[0])):
-        lengths = [len(str(row[i])) for row in rows]
-        widths.append(max(lengths))
-    for row in rows:
-        print("")
-        for i, val in enumerate(row):
-            print str(val).rjust(widths[i]), "|",
-    print("")
-
-
-def run_standard_benchmarks():
-    print("")
-    print("Client Thread Report (1000 requests, 14 byte response body, "
-           "%s server threads):" % cherrypy.server.thread_pool)
-    print_report(thread_report())
-    
-    print("")
-    print("Client Thread Report (1000 requests, 14 bytes via staticdir, "
-           "%s server threads):" % cherrypy.server.thread_pool)
-    print_report(thread_report("%s/static/index.html" % SCRIPT_NAME))
-    
-    print("")
-    print("Size Report (1000 requests, 50 client threads, "
-           "%s server threads):" % cherrypy.server.thread_pool)
-    print_report(size_report())
-
-
-#                         modpython and other WSGI                         #
-
-def startup_modpython(req=None):
-    """Start the CherryPy app server in 'serverless' mode (for modpython/WSGI)."""
-    if cherrypy.engine.state == cherrypy._cpengine.STOPPED:
-        if req:
-            if "nullreq" in req.get_options():
-                cherrypy.engine.request_class = NullRequest
-                cherrypy.engine.response_class = NullResponse
-            ab_opt = req.get_options().get("ab", "")
-            if ab_opt:
-                global AB_PATH
-                AB_PATH = ab_opt
-        cherrypy.engine.start()
-    if cherrypy.engine.state == cherrypy._cpengine.STARTING:
-        cherrypy.engine.wait()
-    return 0 # apache.OK
-
-
-def run_modpython(use_wsgi=False):
-    print("Starting mod_python...")
-    pyopts = []
-    
-    # Pass the null and ab=path options through Apache
-    if "--null" in opts:
-        pyopts.append(("nullreq", ""))
-    
-    if "--ab" in opts:
-        pyopts.append(("ab", opts["--ab"]))
-    
-    s = _cpmodpy.ModPythonServer
-    if use_wsgi:
-        pyopts.append(("wsgi.application", "cherrypy::tree"))
-        pyopts.append(("wsgi.startup", "cherrypy.test.benchmark::startup_modpython"))
-        handler = "modpython_gateway::handler"
-        s = s(port=8080, opts=pyopts, apache_path=APACHE_PATH, handler=handler)
-    else:
-        pyopts.append(("cherrypy.setup", "cherrypy.test.benchmark::startup_modpython"))
-        s = s(port=8080, opts=pyopts, apache_path=APACHE_PATH)
-    
-    try:
-        s.start()
-        run()
-    finally:
-        s.stop()
-
-
-
-if __name__ == '__main__':
-    longopts = ['cpmodpy', 'modpython', 'null', 'notests',
-                'help', 'ab=', 'apache=']
-    try:
-        switches, args = getopt.getopt(sys.argv[1:], "", longopts)
-        opts = dict(switches)
-    except getopt.GetoptError:
-        print(__doc__)
-        sys.exit(2)
-    
-    if "--help" in opts:
-        print(__doc__)
-        sys.exit(0)
-    
-    if "--ab" in opts:
-        AB_PATH = opts['--ab']
-    
-    if "--notests" in opts:
-        # Return without stopping the server, so that the pages
-        # can be tested from a standard web browser.
-        def run():
-            port = cherrypy.server.socket_port
-            print("You may now open http://127.0.0.1:%s%s/" %
-                   (port, SCRIPT_NAME))
-            
-            if "--null" in opts:
-                print("Using null Request object")
-    else:
-        def run():
-            end = time.time() - start
-            print("Started in %s seconds" % end)
-            if "--null" in opts:
-                print("\nUsing null Request object")
-            try:
-                try:
-                    run_standard_benchmarks()
-                except:
-                    print _cperror.format_exc()
-                    raise
-            finally:
-                cherrypy.engine.exit()
-    
-    print("Starting CherryPy app server...")
-    
-    class NullWriter(object):
-        """Suppresses the printing of socket errors."""
-        def write(self, data):
-            pass
-    sys.stderr = NullWriter()
-    
-    start = time.time()
-    
-    if "--cpmodpy" in opts:
-        run_modpython()
-    elif "--modpython" in opts:
-        run_modpython(use_wsgi=True)
-    else:
-        if "--null" in opts:
-            cherrypy.server.request_class = NullRequest
-            cherrypy.server.response_class = NullResponse
-        
-        cherrypy.engine.start_with_callback(run)
-        cherrypy.engine.block()
--- a/bundled/cherrypy/cherrypy/test/checkerdemo.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-"""Demonstration app for cherrypy.checker.
-
-This application is intentionally broken and badly designed.
-To demonstrate the output of the CherryPy Checker, simply execute
-this module.
-"""
-
-import os
-import cherrypy
-thisdir = os.path.dirname(os.path.abspath(__file__))
-
-class Root:
-    pass
-
-if __name__ == '__main__':
-    conf = {'/base': {'tools.staticdir.root': thisdir,
-                      # Obsolete key.
-                      'throw_errors': True,
-                      },
-            # This entry should be OK.
-            '/base/static': {'tools.staticdir.on': True,
-                        'tools.staticdir.dir': 'static'},
-            # Warn on missing folder.
-            '/base/js': {'tools.staticdir.on': True,
-                    'tools.staticdir.dir': 'js'},
-            # Warn on dir with an abs path even though we provide root.
-            '/base/static2': {'tools.staticdir.on': True,
-                         'tools.staticdir.dir': '/static'},
-            # Warn on dir with a relative path with no root.
-            '/static3': {'tools.staticdir.on': True,
-                         'tools.staticdir.dir': 'static'},
-            # Warn on unknown namespace
-            '/unknown': {'toobles.gzip.on': True},
-            # Warn special on cherrypy.<known ns>.*
-            '/cpknown': {'cherrypy.tools.encode.on': True},
-            # Warn on mismatched types
-            '/conftype': {'request.show_tracebacks': 14},
-            # Warn on unknown tool.
-            '/web': {'tools.unknown.on': True},
-            # Warn on server.* in app config.
-            '/app1': {'server.socket_host': '0.0.0.0'},
-            # Warn on 'localhost'
-            'global': {'server.socket_host': 'localhost'},
-            # Warn on '[name]'
-            '[/extra_brackets]': {},
-            }
-    cherrypy.quickstart(Root(), config=conf)
--- a/bundled/cherrypy/cherrypy/test/fcgi.conf	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-
-# Apache2 server conf file for testing CherryPy with mod_fcgid.
-
-DocumentRoot "C:\Python25\Lib\site-packages\cherrypy\test"
-ServerName 127.0.0.1
-Listen 8080
-LoadModule fastcgi_module modules/mod_fastcgi.dll
-LoadModule rewrite_module modules/mod_rewrite.so
-
-Options ExecCGI
-SetHandler fastcgi-script
-RewriteEngine On
-RewriteRule ^(.*)$ /fastcgi.pyc [L]
-FastCgiExternalServer "C:\\Python25\\Lib\\site-packages\\cherrypy\\test\\fastcgi.pyc" -host 127.0.0.1:4000
--- a/bundled/cherrypy/cherrypy/test/helper.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,276 +0,0 @@
-"""A library of helper functions for the CherryPy test suite.
-
-The actual script that runs the entire CP test suite is called
-"test.py" (in this folder); test.py calls this module as a library.
-
-Usage
-=====
-Each individual test_*.py module imports this module (helper),
-usually to make an instance of CPWebCase, and then call testmain().
-
-The CP test suite script (test.py) imports this module and calls
-run_test_suite, possibly more than once. CP applications may also
-import test.py (to use TestHarness), which then calls helper.py.
-"""
-
-# GREAT CARE has been taken to separate this module from test.py,
-# because different consumers of each have mutually-exclusive import
-# requirements. So don't go moving functions from here into test.py,
-# or vice-versa, unless you *really* know what you're doing.
-
-import datetime
-import os
-thisdir = os.path.abspath(os.path.dirname(__file__))
-import re
-import sys
-import time
-import warnings
-
-import cherrypy
-from cherrypy.lib import httputil, profiler
-from cherrypy.test import webtest
-
-
-class CPWebCase(webtest.WebCase):
-    
-    script_name = ""
-    scheme = "http"
-    
-    def prefix(self):
-        return self.script_name.rstrip("/")
-    
-    def base(self):
-        if ((self.scheme == "http" and self.PORT == 80) or
-            (self.scheme == "https" and self.PORT == 443)):
-            port = ""
-        else:
-            port = ":%s" % self.PORT
-        
-        return "%s://%s%s%s" % (self.scheme, self.HOST, port,
-                                self.script_name.rstrip("/"))
-    
-    def exit(self):
-        sys.exit()
-    
-    def getPage(self, url, headers=None, method="GET", body=None, protocol=None):
-        """Open the url. Return status, headers, body."""
-        if self.script_name:
-            url = httputil.urljoin(self.script_name, url)
-        return webtest.WebCase.getPage(self, url, headers, method, body, protocol)
-    
-    def skip(self, msg='skipped '):
-        sys.stderr.write(msg)
-    
-    def assertErrorPage(self, status, message=None, pattern=''):
-        """Compare the response body with a built in error page.
-        
-        The function will optionally look for the regexp pattern,
-        within the exception embedded in the error page."""
-        
-        # This will never contain a traceback
-        page = cherrypy._cperror.get_error_page(status, message=message)
-        
-        # First, test the response body without checking the traceback.
-        # Stick a match-all group (.*) in to grab the traceback.
-        esc = re.escape
-        epage = esc(page)
-        epage = epage.replace(esc('<pre id="traceback"></pre>'),
-                              esc('<pre id="traceback">') + '(.*)' + esc('</pre>'))
-        m = re.match(epage, self.body, re.DOTALL)
-        if not m:
-            self._handlewebError('Error page does not match; expected:\n' + page)
-            return
-        
-        # Now test the pattern against the traceback
-        if pattern is None:
-            # Special-case None to mean that there should be *no* traceback.
-            if m and m.group(1):
-                self._handlewebError('Error page contains traceback')
-        else:
-            if (m is None) or (
-                not re.search(re.escape(pattern),
-                              m.group(1))):
-                msg = 'Error page does not contain %s in traceback'
-                self._handlewebError(msg % repr(pattern))
-    
-    date_tolerance = 2
-    
-    def assertEqualDates(self, dt1, dt2, seconds=None):
-        """Assert abs(dt1 - dt2) is within Y seconds."""
-        if seconds is None:
-            seconds = self.date_tolerance
-        
-        if dt1 > dt2:
-            diff = dt1 - dt2
-        else:
-            diff = dt2 - dt1
-        if not diff < datetime.timedelta(seconds=seconds):
-            raise AssertionError('%r and %r are not within %r seconds.' %
-                                 (dt1, dt2, seconds))
-
-
-CPTestLoader = webtest.ReloadingTestLoader()
-CPTestRunner = webtest.TerseTestRunner(verbosity=2)
-
-
-def run_test_suite(moduleNames, conf, supervisor):
-    """Run the given test modules using the given supervisor and [global] conf.
-    
-    The 'supervisor' arg should be an object with 'start' and 'stop' methods.
-    See test/test.py.
-    """
-    # The Pybots automatic testing system needs the suite to exit
-    # with a non-zero value if there were any problems.
-    test_success = True
-    
-    for testmod in moduleNames:
-        cherrypy.config.reset()
-        cherrypy.config.update(conf)
-        setup_client(supervisor)
-        
-        if '.' in testmod:
-            package, test_name = testmod.rsplit('.', 1)
-            p = __import__(package, globals(), locals(), fromlist=[test_name])
-            m = getattr(p, test_name)
-        else:
-            m = __import__(testmod, globals(), locals())
-        suite = CPTestLoader.loadTestsFromName(testmod)
-        
-        setup = getattr(m, "setup_server", None)
-        if setup: supervisor.start(testmod)
-        try:
-            result = CPTestRunner.run(suite)
-            test_success &= result.wasSuccessful()
-        finally:
-            if setup: supervisor.stop()
-    
-    if test_success:
-        return 0
-    else:
-        return 1
-
-def setup_client(supervisor):
-    """Set up the WebCase classes to match the server's socket settings."""
-    webtest.WebCase.PORT = cherrypy.server.socket_port
-    webtest.WebCase.HOST = cherrypy.server.socket_host
-    if cherrypy.server.ssl_certificate:
-        CPWebCase.scheme = 'https'
-
-def testmain(conf=None):
-    """Run __main__ as a test module, with webtest debugging."""
-    # Comment me out to see ENGINE messages etc. when running a test standalone.
-    cherrypy.config.update({'environment': "test_suite"})
-    cherrypy.server.socket_host = '127.0.0.1'
-    
-    from cherrypy.test.test import LocalWSGISupervisor
-    supervisor = LocalWSGISupervisor(host=cherrypy.server.socket_host,
-                                     port=cherrypy.server.socket_port)
-    setup_client(supervisor)
-    supervisor.start('__main__')
-    try:
-        return webtest.main()
-    finally:
-        supervisor.stop()
-
-
-
-# --------------------------- Spawning helpers --------------------------- #
-
-
-class CPProcess(object):
-    
-    pid_file = os.path.join(thisdir, 'test.pid')
-    config_file = os.path.join(thisdir, 'test.conf')
-    config_template = """[global]
-server.socket_host: '%(host)s'
-server.socket_port: %(port)s
-checker.on: False
-log.screen: False
-log.error_file: r'%(error_log)s'
-log.access_file: r'%(access_log)s'
-%(ssl)s
-%(extra)s
-"""
-    error_log = os.path.join(thisdir, 'test.error.log')
-    access_log = os.path.join(thisdir, 'test.access.log')
-    
-    def __init__(self, wait=False, daemonize=False, ssl=False, socket_host=None, socket_port=None):
-        self.wait = wait
-        self.daemonize = daemonize
-        self.ssl = ssl
-        self.host = socket_host or cherrypy.server.socket_host
-        self.port = socket_port or cherrypy.server.socket_port
-    
-    def write_conf(self, extra=""):
-        if self.ssl:
-            serverpem = os.path.join(thisdir, 'test.pem')
-            ssl = """
-server.ssl_certificate: r'%s'
-server.ssl_private_key: r'%s'
-""" % (serverpem, serverpem)
-        else:
-            ssl = ""
-        
-        conf = self.config_template % {
-            'host': self.host,
-            'port': self.port,
-            'error_log': self.error_log,
-            'access_log': self.access_log,
-            'ssl': ssl,
-            'extra': extra,
-            }
-        f = open(self.config_file, 'wb')
-        f.write(conf)
-        f.close()
-    
-    def start(self, imports=None):
-        """Start cherryd in a subprocess."""
-        cherrypy._cpserver.wait_for_free_port(self.host, self.port)
-        
-        args = [sys.executable, os.path.join(thisdir, '..', 'cherryd'),
-                '-c', self.config_file, '-p', self.pid_file]
-        
-        if not isinstance(imports, (list, tuple)):
-            imports = [imports]
-        for i in imports:
-            if i:
-                args.append('-i')
-                args.append(i)
-        
-        if self.daemonize:
-            args.append('-d')
-        
-        if self.wait:
-            self.exit_code = os.spawnl(os.P_WAIT, sys.executable, *args)
-        else:
-            os.spawnl(os.P_NOWAIT, sys.executable, *args)
-            cherrypy._cpserver.wait_for_occupied_port(self.host, self.port)
-        
-        # Give the engine a wee bit more time to finish STARTING
-        if self.daemonize:
-            time.sleep(2)
-        else:
-            time.sleep(1)
-    
-    def get_pid(self):
-        return int(open(self.pid_file, 'rb').read())
-    
-    def join(self):
-        """Wait for the process to exit."""
-        try:
-            try:
-                # Mac, UNIX
-                os.wait()
-            except AttributeError:
-                # Windows
-                try:
-                    pid = self.get_pid()
-                except IOError:
-                    # Assume the subprocess deleted the pidfile on shutdown.
-                    pass
-                else:
-                    os.waitpid(pid, 0)
-        except OSError, x:
-            if x.args != (10, 'No child processes'):
-                raise
-
--- a/bundled/cherrypy/cherrypy/test/logtest.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,181 +0,0 @@
-"""logtest, a unittest.TestCase helper for testing log output."""
-
-import sys
-import time
-
-import cherrypy
-
-
-try:
-    # On Windows, msvcrt.getch reads a single char without output.
-    import msvcrt
-    def getchar():
-        return msvcrt.getch()
-except ImportError:
-    # Unix getchr
-    import tty, termios
-    def getchar():
-        fd = sys.stdin.fileno()
-        old_settings = termios.tcgetattr(fd)
-        try:
-            tty.setraw(sys.stdin.fileno())
-            ch = sys.stdin.read(1)
-        finally:
-            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
-        return ch
-
-
-class LogCase(object):
-    """unittest.TestCase mixin for testing log messages.
-    
-    logfile: a filename for the desired log. Yes, I know modes are evil,
-        but it makes the test functions so much cleaner to set this once.
-    
-    lastmarker: the last marker in the log. This can be used to search for
-        messages since the last marker.
-    
-    markerPrefix: a string with which to prefix log markers. This should be
-        unique enough from normal log output to use for marker identification.
-    """
-    
-    logfile = None
-    lastmarker = None
-    markerPrefix = "test suite marker: "
-    
-    def _handleLogError(self, msg, data, marker, pattern):
-        print("")
-        print("    ERROR: %s" % msg)
-        
-        if not self.interactive:
-            raise self.failureException(msg)
-        
-        p = "    Show: [L]og [M]arker [P]attern; [I]gnore, [R]aise, or sys.e[X]it >> "
-        print p,
-        # ARGH
-        sys.stdout.flush()
-        while True:
-            i = getchar().upper()
-            if i not in "MPLIRX":
-                continue
-            print(i.upper())  # Also prints new line
-            if i == "L":
-                for x, line in enumerate(data):
-                    if (x + 1) % self.console_height == 0:
-                        # The \r and comma should make the next line overwrite
-                        print "<-- More -->\r",
-                        m = getchar().lower()
-                        # Erase our "More" prompt
-                        print "            \r",
-                        if m == "q":
-                            break
-                    print(line.rstrip())
-            elif i == "M":
-                print(repr(marker or self.lastmarker))
-            elif i == "P":
-                print(repr(pattern))
-            elif i == "I":
-                # return without raising the normal exception
-                return
-            elif i == "R":
-                raise self.failureException(msg)
-            elif i == "X":
-                self.exit()
-            print p,
-    
-    def exit(self):
-        sys.exit()
-    
-    def emptyLog(self):
-        """Overwrite self.logfile with 0 bytes."""
-        open(self.logfile, 'wb').write("")
-    
-    def markLog(self, key=None):
-        """Insert a marker line into the log and set self.lastmarker."""
-        if key is None:
-            key = str(time.time())
-        self.lastmarker = key
-        
-        open(self.logfile, 'ab+').write("%s%s\n" % (self.markerPrefix, key))
-    
-    def _read_marked_region(self, marker=None):
-        """Return lines from self.logfile in the marked region.
-        
-        If marker is None, self.lastmarker is used. If the log hasn't
-        been marked (using self.markLog), the entire log will be returned.
-        """
-##        # Give the logger time to finish writing?
-##        time.sleep(0.5)
-        
-        logfile = self.logfile
-        marker = marker or self.lastmarker
-        if marker is None:
-            return open(logfile, 'rb').readlines()
-        
-        data = []
-        in_region = False
-        for line in open(logfile, 'rb'):
-            if in_region:
-                if (line.startswith(self.markerPrefix) and not marker in line):
-                    break
-                else:
-                    data.append(line)
-            elif marker in line:
-                in_region = True
-        return data
-    
-    def assertInLog(self, line, marker=None):
-        """Fail if the given (partial) line is not in the log.
-        
-        The log will be searched from the given marker to the next marker.
-        If marker is None, self.lastmarker is used. If the log hasn't
-        been marked (using self.markLog), the entire log will be searched.
-        """
-        data = self._read_marked_region(marker)
-        for logline in data:
-            if line in logline:
-                return
-        msg = "%r not found in log" % line
-        self._handleLogError(msg, data, marker, line)
-    
-    def assertNotInLog(self, line, marker=None):
-        """Fail if the given (partial) line is in the log.
-        
-        The log will be searched from the given marker to the next marker.
-        If marker is None, self.lastmarker is used. If the log hasn't
-        been marked (using self.markLog), the entire log will be searched.
-        """
-        data = self._read_marked_region(marker)
-        for logline in data:
-            if line in logline:
-                msg = "%r found in log" % line
-                self._handleLogError(msg, data, marker, line)
-    
-    def assertLog(self, sliceargs, lines, marker=None):
-        """Fail if log.readlines()[sliceargs] is not contained in 'lines'.
-        
-        The log will be searched from the given marker to the next marker.
-        If marker is None, self.lastmarker is used. If the log hasn't
-        been marked (using self.markLog), the entire log will be searched.
-        """
-        data = self._read_marked_region(marker)
-        if isinstance(sliceargs, int):
-            # Single arg. Use __getitem__ and allow lines to be str or list.
-            if isinstance(lines, (tuple, list)):
-                lines = lines[0]
-            if lines not in data[sliceargs]:
-                msg = "%r not found on log line %r" % (lines, sliceargs)
-                self._handleLogError(msg, [data[sliceargs]], marker, lines)
-        else:
-            # Multiple args. Use __getslice__ and require lines to be list.
-            if isinstance(lines, tuple):
-                lines = list(lines)
-            elif isinstance(lines, basestring):
-                raise TypeError("The 'lines' arg must be a list when "
-                                "'sliceargs' is a tuple.")
-            
-            start, stop = sliceargs
-            for line, logline in zip(lines, data[start:stop]):
-                if line not in logline:
-                    msg = "%r not found in log" % line
-                    self._handleLogError(msg, data[start:stop], marker, line)
-
--- a/bundled/cherrypy/cherrypy/test/modfcgid.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,124 +0,0 @@
-"""Wrapper for mod_fcgid, for use as a CherryPy HTTP server when testing.
-
-To autostart fcgid, the "apache" executable or script must be
-on your system path, or you must override the global APACHE_PATH.
-On some platforms, "apache" may be called "apachectl", "apache2ctl",
-or "httpd"--create a symlink to them if needed.
-
-You'll also need the WSGIServer from flup.servers.
-See http://projects.amor.org/misc/wiki/ModPythonGateway
-
-
-KNOWN BUGS
-==========
-
-1. Apache processes Range headers automatically; CherryPy's truncated
-    output is then truncated again by Apache. See test_core.testRanges.
-    This was worked around in http://www.cherrypy.org/changeset/1319.
-2. Apache does not allow custom HTTP methods like CONNECT as per the spec.
-    See test_core.testHTTPMethods.
-3. Max request header and body settings do not work with Apache.
-4. Apache replaces status "reason phrases" automatically. For example,
-    CherryPy may set "304 Not modified" but Apache will write out
-    "304 Not Modified" (capital "M").
-5. Apache does not allow custom error codes as per the spec.
-6. Apache (or perhaps modpython, or modpython_gateway) unquotes %xx in the
-    Request-URI too early.
-7. mod_python will not read request bodies which use the "chunked"
-    transfer-coding (it passes REQUEST_CHUNKED_ERROR to ap_setup_client_block
-    instead of REQUEST_CHUNKED_DECHUNK, see Apache2's http_protocol.c and
-    mod_python's requestobject.c).
-8. Apache will output a "Content-Length: 0" response header even if there's
-    no response entity body. This isn't really a bug; it just differs from
-    the CherryPy default.
-"""
-
-import os
-curdir = os.path.join(os.getcwd(), os.path.dirname(__file__))
-import re
-import sys
-import time
-
-import cherrypy
-from cherrypy.process import plugins, servers
-from cherrypy.test import test
-
-
-def read_process(cmd, args=""):
-    pipein, pipeout = os.popen4("%s %s" % (cmd, args))
-    try:
-        firstline = pipeout.readline()
-        if (re.search(r"(not recognized|No such file|not found)", firstline,
-                      re.IGNORECASE)):
-            raise IOError('%s must be on your system path.' % cmd)
-        output = firstline + pipeout.read()
-    finally:
-        pipeout.close()
-    return output
-
-
-APACHE_PATH = "httpd"
-CONF_PATH = "fcgi.conf"
-
-conf_fcgid = """
-# Apache2 server conf file for testing CherryPy with mod_fcgid.
-
-DocumentRoot "%(root)s"
-ServerName 127.0.0.1
-Listen %(port)s
-LoadModule fastcgi_module modules/mod_fastcgi.dll
-LoadModule rewrite_module modules/mod_rewrite.so
-
-Options ExecCGI
-SetHandler fastcgi-script
-RewriteEngine On
-RewriteRule ^(.*)$ /fastcgi.pyc [L]
-FastCgiExternalServer "%(server)s" -host 127.0.0.1:4000
-"""
-
-class ModFCGISupervisor(test.LocalSupervisor):
-    
-    using_apache = True
-    using_wsgi = True
-    template = conf_fcgid
-    
-    def __str__(self):
-        return "FCGI Server on %s:%s" % (self.host, self.port)
-    
-    def start(self, modulename):
-        cherrypy.server.httpserver = servers.FlupFCGIServer(
-            application=cherrypy.tree, bindAddress=('127.0.0.1', 4000))
-        cherrypy.server.httpserver.bind_addr = ('127.0.0.1', 4000)
-        # For FCGI, we both start apache...
-        self.start_apache()
-        # ...and our local server
-        test.LocalServer.start(self, modulename)
-    
-    def start_apache(self):
-        fcgiconf = CONF_PATH
-        if not os.path.isabs(fcgiconf):
-            fcgiconf = os.path.join(curdir, fcgiconf)
-        
-        # Write the Apache conf file.
-        f = open(fcgiconf, 'wb')
-        try:
-            server = repr(os.path.join(curdir, 'fastcgi.pyc'))[1:-1]
-            output = self.template % {'port': self.port, 'root': curdir,
-                                      'server': server}
-            output = output.replace('\r\n', '\n')
-            f.write(output)
-        finally:
-            f.close()
-        
-        result = read_process(APACHE_PATH, "-k start -f %s" % fcgiconf)
-        if result:
-            print(result)
-    
-    def stop(self):
-        """Gracefully shutdown a server that is serving forever."""
-        read_process(APACHE_PATH, "-k stop")
-        test.LocalServer.stop(self)
-    
-    def sync_apps(self):
-        cherrypy.server.httpserver.fcgiserver.application = self.get_app()
-
--- a/bundled/cherrypy/cherrypy/test/modpy.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,163 +0,0 @@
-"""Wrapper for mod_python, for use as a CherryPy HTTP server when testing.
-
-To autostart modpython, the "apache" executable or script must be
-on your system path, or you must override the global APACHE_PATH.
-On some platforms, "apache" may be called "apachectl" or "apache2ctl"--
-create a symlink to them if needed.
-
-If you wish to test the WSGI interface instead of our _cpmodpy interface,
-you also need the 'modpython_gateway' module at:
-http://projects.amor.org/misc/wiki/ModPythonGateway
-
-
-KNOWN BUGS
-==========
-
-1. Apache processes Range headers automatically; CherryPy's truncated
-    output is then truncated again by Apache. See test_core.testRanges.
-    This was worked around in http://www.cherrypy.org/changeset/1319.
-2. Apache does not allow custom HTTP methods like CONNECT as per the spec.
-    See test_core.testHTTPMethods.
-3. Max request header and body settings do not work with Apache.
-4. Apache replaces status "reason phrases" automatically. For example,
-    CherryPy may set "304 Not modified" but Apache will write out
-    "304 Not Modified" (capital "M").
-5. Apache does not allow custom error codes as per the spec.
-6. Apache (or perhaps modpython, or modpython_gateway) unquotes %xx in the
-    Request-URI too early.
-7. mod_python will not read request bodies which use the "chunked"
-    transfer-coding (it passes REQUEST_CHUNKED_ERROR to ap_setup_client_block
-    instead of REQUEST_CHUNKED_DECHUNK, see Apache2's http_protocol.c and
-    mod_python's requestobject.c).
-8. Apache will output a "Content-Length: 0" response header even if there's
-    no response entity body. This isn't really a bug; it just differs from
-    the CherryPy default.
-"""
-
-import os
-curdir = os.path.join(os.getcwd(), os.path.dirname(__file__))
-import re
-import time
-
-from cherrypy.test import test
-
-
-def read_process(cmd, args=""):
-    pipein, pipeout = os.popen4("%s %s" % (cmd, args))
-    try:
-        firstline = pipeout.readline()
-        if (re.search(r"(not recognized|No such file|not found)", firstline,
-                      re.IGNORECASE)):
-            raise IOError('%s must be on your system path.' % cmd)
-        output = firstline + pipeout.read()
-    finally:
-        pipeout.close()
-    return output
-
-
-APACHE_PATH = "httpd"
-CONF_PATH = "test_mp.conf"
-
-conf_modpython_gateway = """
-# Apache2 server conf file for testing CherryPy with modpython_gateway.
-
-ServerName 127.0.0.1
-DocumentRoot "/"
-Listen %(port)s
-LoadModule python_module modules/mod_python.so
-
-SetHandler python-program
-PythonFixupHandler cherrypy.test.modpy::wsgisetup
-PythonOption testmod %(modulename)s
-PythonHandler modpython_gateway::handler
-PythonOption wsgi.application cherrypy::tree
-PythonOption socket_host %(host)s
-PythonDebug On
-"""
-
-conf_cpmodpy = """
-# Apache2 server conf file for testing CherryPy with _cpmodpy.
-
-ServerName 127.0.0.1
-DocumentRoot "/"
-Listen %(port)s
-LoadModule python_module modules/mod_python.so
-
-SetHandler python-program
-PythonFixupHandler cherrypy.test.modpy::cpmodpysetup
-PythonHandler cherrypy._cpmodpy::handler
-PythonOption cherrypy.setup cherrypy.test.%(modulename)s::setup_server
-PythonOption socket_host %(host)s
-PythonDebug On
-"""
-
-class ModPythonSupervisor(test.Supervisor):
-    
-    using_apache = True
-    using_wsgi = False
-    template = None
-    
-    def __str__(self):
-        return "ModPython Server on %s:%s" % (self.host, self.port)
-    
-    def start(self, modulename):
-        mpconf = CONF_PATH
-        if not os.path.isabs(mpconf):
-            mpconf = os.path.join(curdir, mpconf)
-        
-        f = open(mpconf, 'wb')
-        try:
-            f.write(self.template %
-                    {'port': self.port, 'modulename': modulename,
-                     'host': self.host})
-        finally:
-            f.close()
-        
-        result = read_process(APACHE_PATH, "-k start -f %s" % mpconf)
-        if result:
-            print(result)
-    
-    def stop(self):
-        """Gracefully shutdown a server that is serving forever."""
-        read_process(APACHE_PATH, "-k stop")
-
-
-loaded = False
-def wsgisetup(req):
-    global loaded
-    if not loaded:
-        loaded = True
-        options = req.get_options()
-        
-        import cherrypy
-        cherrypy.config.update({
-            "log.error_file": os.path.join(curdir, "test.log"),
-            "environment": "test_suite",
-            "server.socket_host": options['socket_host'],
-            })
-        
-        modname = options['testmod']
-        mod = __import__(modname, globals(), locals(), [''])
-        mod.setup_server()
-        
-        cherrypy.server.unsubscribe()
-        cherrypy.engine.start()
-    from mod_python import apache
-    return apache.OK
-
-
-def cpmodpysetup(req):
-    global loaded
-    if not loaded:
-        loaded = True
-        options = req.get_options()
-        
-        import cherrypy
-        cherrypy.config.update({
-            "log.error_file": os.path.join(curdir, "test.log"),
-            "environment": "test_suite",
-            "server.socket_host": options['socket_host'],
-            })
-    from mod_python import apache
-    return apache.OK
-
--- a/bundled/cherrypy/cherrypy/test/modwsgi.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,148 +0,0 @@
-"""Wrapper for mod_wsgi, for use as a CherryPy HTTP server.
-
-To autostart modwsgi, the "apache" executable or script must be
-on your system path, or you must override the global APACHE_PATH.
-On some platforms, "apache" may be called "apachectl" or "apache2ctl"--
-create a symlink to them if needed.
-
-
-KNOWN BUGS
-==========
-
-##1. Apache processes Range headers automatically; CherryPy's truncated
-##    output is then truncated again by Apache. See test_core.testRanges.
-##    This was worked around in http://www.cherrypy.org/changeset/1319.
-2. Apache does not allow custom HTTP methods like CONNECT as per the spec.
-    See test_core.testHTTPMethods.
-3. Max request header and body settings do not work with Apache.
-##4. Apache replaces status "reason phrases" automatically. For example,
-##    CherryPy may set "304 Not modified" but Apache will write out
-##    "304 Not Modified" (capital "M").
-##5. Apache does not allow custom error codes as per the spec.
-##6. Apache (or perhaps modpython, or modpython_gateway) unquotes %xx in the
-##    Request-URI too early.
-7. mod_wsgi will not read request bodies which use the "chunked"
-    transfer-coding (it passes REQUEST_CHUNKED_ERROR to ap_setup_client_block
-    instead of REQUEST_CHUNKED_DECHUNK, see Apache2's http_protocol.c and
-    mod_python's requestobject.c).
-8. When responding with 204 No Content, mod_wsgi adds a Content-Length
-    header for you.
-9. When an error is raised, mod_wsgi has no facility for printing a
-    traceback as the response content (it's sent to the Apache log instead).
-10. Startup and shutdown of Apache when running mod_wsgi seems slow.
-"""
-
-import os
-curdir = os.path.abspath(os.path.dirname(__file__))
-import re
-import sys
-import time
-
-import cherrypy
-from cherrypy.test import test, webtest
-
-
-def read_process(cmd, args=""):
-    pipein, pipeout = os.popen4("%s %s" % (cmd, args))
-    try:
-        firstline = pipeout.readline()
-        if (re.search(r"(not recognized|No such file|not found)", firstline,
-                      re.IGNORECASE)):
-            raise IOError('%s must be on your system path.' % cmd)
-        output = firstline + pipeout.read()
-    finally:
-        pipeout.close()
-    return output
-
-
-if sys.platform == 'win32':
-    APACHE_PATH = "httpd"
-else:
-    APACHE_PATH = "apache"
-
-CONF_PATH = "test_mw.conf"
-
-conf_modwsgi = r"""
-# Apache2 server conf file for testing CherryPy with modpython_gateway.
-
-ServerName 127.0.0.1
-DocumentRoot "/"
-Listen %(port)s
-
-AllowEncodedSlashes On
-LoadModule rewrite_module modules/mod_rewrite.so
-RewriteEngine on
-RewriteMap escaping int:escape
-
-LoadModule log_config_module modules/mod_log_config.so
-LogFormat "%%h %%l %%u %%t \"%%r\" %%>s %%b \"%%{Referer}i\" \"%%{User-agent}i\"" combined
-CustomLog "%(curdir)s/apache.access.log" combined
-ErrorLog "%(curdir)s/apache.error.log"
-LogLevel debug
-
-LoadModule wsgi_module modules/mod_wsgi.so
-LoadModule env_module modules/mod_env.so
-
-WSGIScriptAlias / "%(curdir)s/modwsgi.py"
-SetEnv testmod %(testmod)s
-"""
-
-
-class ModWSGISupervisor(test.Supervisor):
-    """Server Controller for ModWSGI and CherryPy."""
-    
-    using_apache = True
-    using_wsgi = True
-    template=conf_modwsgi
-    
-    def __str__(self):
-        return "ModWSGI Server on %s:%s" % (self.host, self.port)
-    
-    def start(self, modulename):
-        mpconf = CONF_PATH
-        if not os.path.isabs(mpconf):
-            mpconf = os.path.join(curdir, mpconf)
-        
-        f = open(mpconf, 'wb')
-        try:
-            output = (self.template %
-                      {'port': self.port, 'testmod': modulename,
-                       'curdir': curdir})
-            f.write(output)
-        finally:
-            f.close()
-        
-        result = read_process(APACHE_PATH, "-k start -f %s" % mpconf)
-        if result:
-            print(result)
-        
-        # Make a request so mod_wsgi starts up our app.
-        # If we don't, concurrent initial requests will 404.
-        cherrypy._cpserver.wait_for_occupied_port("127.0.0.1", self.port)
-        webtest.openURL('/ihopetheresnodefault', port=self.port)
-        time.sleep(1)
-    
-    def stop(self):
-        """Gracefully shutdown a server that is serving forever."""
-        read_process(APACHE_PATH, "-k stop")
-
-
-loaded = False
-def application(environ, start_response):
-    import cherrypy
-    global loaded
-    if not loaded:
-        loaded = True
-        modname = "cherrypy.test." + environ['testmod']
-        mod = __import__(modname, globals(), locals(), [''])
-        mod.setup_server()
-        
-        cherrypy.config.update({
-            "log.error_file": os.path.join(curdir, "test.error.log"),
-            "log.access_file": os.path.join(curdir, "test.access.log"),
-            "environment": "test_suite",
-            "engine.SIGHUP": None,
-            "engine.SIGTERM": None,
-            })
-    return cherrypy.tree(environ, start_response)
-
--- a/bundled/cherrypy/cherrypy/test/py25.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-"""Test module for Python 2.5-specific syntax, like the @-decorator syntax."""
-
-from cherrypy import expose, tools
-
-
-class ExposeExamples(object):
-    
-    @expose
-    def no_call(self):
-        return "Mr E. R. Bradshaw"
-    
-    @expose()
-    def call_empty(self):
-        return "Mrs. B.J. Smegma"
-    
-    @expose("call_alias")
-    def nesbitt(self):
-        return "Mr Nesbitt"
-    
-    @expose(["alias1", "alias2"])
-    def andrews(self):
-        return "Mr Ken Andrews"
-    
-    @expose(alias="alias3")
-    def watson(self):
-        return "Mr. and Mrs. Watson"
-
-
-class ToolExamples(object):
-    
-    @expose
-    @tools.response_headers(headers=[('Content-Type', 'application/data')])
-    def blah(self):
-        yield "blah"
-    # This is here to demonstrate that _cp_config = {...} overwrites
-    # the _cp_config attribute added by the Tool decorator. You have
-    # to write _cp_config[k] = v or _cp_config.update(...) instead.
-    blah._cp_config['response.stream'] = True
-
-
--- a/bundled/cherrypy/cherrypy/test/sessiondemo.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,152 +0,0 @@
-#!/usr/bin/python
-"""A session demonstration app."""
-
-import calendar
-from datetime import datetime
-import sys
-import cherrypy
-from cherrypy.lib import sessions
-
-
-page = """
-<html>
-<head>
-<style type='text/css'>
-table { border-collapse: collapse; border: 1px solid #663333; }
-th { text-align: right; background-color: #663333; color: white; padding: 0.5em; }
-td { white-space: pre-wrap; font-family: monospace; padding: 0.5em; 
-     border: 1px solid #663333; }
-.warn { font-family: serif; color: #990000; }
-</style>
-<script type="text/javascript">
-<!--
-function twodigit(d) { return d < 10 ? "0" + d : d; }
-function formattime(t) {
-    var month = t.getUTCMonth() + 1;
-    var day = t.getUTCDate();
-    var year = t.getUTCFullYear();
-    var hours = t.getUTCHours();
-    var minutes = t.getUTCMinutes();
-    return (year + "/" + twodigit(month) + "/" + twodigit(day) + " " +
-            hours + ":" + twodigit(minutes) + " UTC");
-}
-
-function interval(s) {
-    // Return the given interval (in seconds) as an English phrase
-    var seconds = s %% 60;
-    s = Math.floor(s / 60);
-    var minutes = s %% 60;
-    s = Math.floor(s / 60);
-    var hours = s %% 24;
-    var v = twodigit(hours) + ":" + twodigit(minutes) + ":" + twodigit(seconds);
-    var days = Math.floor(s / 24);
-    if (days != 0) v = days + ' days, ' + v;
-    return v;
-}
-
-var fudge_seconds = 5;
-
-function init() {
-    // Set the content of the 'btime' cell.
-    var currentTime = new Date();
-    var bunixtime = Math.floor(currentTime.getTime() / 1000);
-    
-    var v = formattime(currentTime);
-    v += " (Unix time: " + bunixtime + ")";
-    
-    var diff = Math.abs(%(serverunixtime)s - bunixtime);
-    if (diff > fudge_seconds) v += "<p class='warn'>Browser and Server times disagree.</p>";
-    
-    document.getElementById('btime').innerHTML = v;
-    
-    // Warn if response cookie expires is not close to one hour in the future.
-    // Yes, we want this to happen when wit hit the 'Expire' link, too.
-    var expires = Date.parse("%(expires)s") / 1000;
-    var onehour = (60 * 60);
-    if (Math.abs(expires - (bunixtime + onehour)) > fudge_seconds) {
-        diff = Math.floor(expires - bunixtime);
-        if (expires > (bunixtime + onehour)) {
-            var msg = "Response cookie 'expires' date is " + interval(diff) + " in the future.";
-        } else {
-            var msg = "Response cookie 'expires' date is " + interval(0 - diff) + " in the past.";
-        }
-        document.getElementById('respcookiewarn').innerHTML = msg;
-    }
-}
-//-->
-</script>
-</head>
-
-<body onload='init()'>
-<h2>Session Demo</h2>
-<p>Reload this page. The session ID should not change from one reload to the next</p>
-<p><a href='../'>Index</a> | <a href='expire'>Expire</a> | <a href='regen'>Regenerate</a></p>
-<table>
-    <tr><th>Session ID:</th><td>%(sessionid)s<p class='warn'>%(changemsg)s</p></td></tr>
-    <tr><th>Request Cookie</th><td>%(reqcookie)s</td></tr>
-    <tr><th>Response Cookie</th><td>%(respcookie)s<p id='respcookiewarn' class='warn'></p></td></tr>
-    <tr><th>Session Data</th><td>%(sessiondata)s</td></tr>
-    <tr><th>Server Time</th><td id='stime'>%(servertime)s (Unix time: %(serverunixtime)s)</td></tr>
-    <tr><th>Browser Time</th><td id='btime'>&nbsp;</td></tr>
-    <tr><th>Cherrypy Version:</th><td>%(cpversion)s</td></tr>
-    <tr><th>Python Version:</th><td>%(pyversion)s</td></tr>
-</table>
-</body></html>
-"""
-
-class Root(object):
-    
-    def page(self):
-        changemsg = []
-        if cherrypy.session.id != cherrypy.session.originalid:
-            if cherrypy.session.originalid is None:
-                changemsg.append('Created new session because no session id was given.')
-            if cherrypy.session.missing:
-                changemsg.append('Created new session due to missing (expired or malicious) session.')
-            if cherrypy.session.regenerated:
-                changemsg.append('Application generated a new session.')
-        
-        try:
-            expires = cherrypy.response.cookie['session_id']['expires']
-        except KeyError:
-            expires = ''
-        
-        return page % {
-            'sessionid': cherrypy.session.id,
-            'changemsg': '<br>'.join(changemsg),
-            'respcookie': cherrypy.response.cookie.output(),
-            'reqcookie': cherrypy.request.cookie.output(),
-            'sessiondata': cherrypy.session.items(),
-            'servertime': datetime.utcnow().strftime("%Y/%m/%d %H:%M") + " UTC",
-            'serverunixtime': calendar.timegm(datetime.utcnow().timetuple()),
-            'cpversion': cherrypy.__version__,
-            'pyversion': sys.version,
-            'expires': expires,
-            }
-    
-    def index(self):
-        # Must modify data or the session will not be saved.
-        cherrypy.session['color'] = 'green'
-        return self.page()
-    index.exposed = True
-    
-    def expire(self):
-        sessions.expire()
-        return self.page()
-    expire.exposed = True
-    
-    def regen(self):
-        cherrypy.session.regenerate()
-        # Must modify data or the session will not be saved.
-        cherrypy.session['color'] = 'yellow'
-        return self.page()
-    regen.exposed = True
-
-if __name__ == '__main__':
-    cherrypy.config.update({
-        #'environment': 'production',
-        'log.screen': True,
-        'tools.sessions.on': True,
-        })
-    cherrypy.quickstart(Root())
-
Binary file bundled/cherrypy/cherrypy/test/static/dirback.jpg has changed
--- a/bundled/cherrypy/cherrypy/test/static/index.html	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-Hello, world
--- a/bundled/cherrypy/cherrypy/test/style.css	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-Dummy stylesheet
--- a/bundled/cherrypy/cherrypy/test/test.pem	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIICXAIBAAKBgQDBKo554mzIMY+AByUNpaUOP9bJnQ7ZLQe9XgHwoLJR4VzpyZZZ
-R9L4WtImEew05FY3Izerfm3MN3+MC0tJ6yQU9sOiU3vBW6RrLIMlfKsnRwBRZ0Kn
-da+O6xldVSosu8Ev3z9VZ94iC/ZgKzrH7Mjj/U8/MQO7RBS/LAqee8bFNQIDAQAB
-AoGAWOCF0ZrWxn3XMucWq2LNwPKqlvVGwbIwX3cDmX22zmnM4Fy6arXbYh4XlyCj
-9+ofqRrxIFz5k/7tFriTmZ0xag5+Jdx+Kwg0/twiP7XCNKipFogwe1Hznw8OFAoT
-enKBdj2+/n2o0Bvo/tDB59m9L/538d46JGQUmJlzMyqYikECQQDyoq+8CtMNvE18
-8VgHcR/KtApxWAjj4HpaHYL637ATjThetUZkW92mgDgowyplthusxdNqhHWyv7E8
-tWNdYErZAkEAy85ShTR0M5aWmrE7o0r0SpWInAkNBH9aXQRRARFYsdBtNfRu6I0i
-0lvU9wiu3eF57FMEC86yViZ5UBnQfTu7vQJAVesj/Zt7pwaCDfdMa740OsxMUlyR
-MVhhGx4OLpYdPJ8qUecxGQKq13XZ7R1HGyNEY4bd2X80Smq08UFuATfC6QJAH8UB
-yBHtKz2GLIcELOg6PIYizW/7v3+6rlVF60yw7sb2vzpjL40QqIn4IKoR2DSVtOkb
-8FtAIX3N21aq0VrGYQJBAIPiaEc2AZ8Bq2GC4F3wOz/BxJ/izvnkiotR12QK4fh5
-yjZMhTjWCas5zwHR5PDjlD88AWGDMsZ1PicD4348xJQ=
------END RSA PRIVATE KEY-----
------BEGIN CERTIFICATE-----
-MIIDxTCCAy6gAwIBAgIJAI18BD7eQxlGMA0GCSqGSIb3DQEBBAUAMIGeMQswCQYD
-VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTESMBAGA1UEBxMJU2FuIERpZWdv
-MRkwFwYDVQQKExBDaGVycnlQeSBQcm9qZWN0MREwDwYDVQQLEwhkZXYtdGVzdDEW
-MBQGA1UEAxMNQ2hlcnJ5UHkgVGVhbTEgMB4GCSqGSIb3DQEJARYRcmVtaUBjaGVy
-cnlweS5vcmcwHhcNMDYwOTA5MTkyMDIwWhcNMzQwMTI0MTkyMDIwWjCBnjELMAkG
-A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVNhbiBEaWVn
-bzEZMBcGA1UEChMQQ2hlcnJ5UHkgUHJvamVjdDERMA8GA1UECxMIZGV2LXRlc3Qx
-FjAUBgNVBAMTDUNoZXJyeVB5IFRlYW0xIDAeBgkqhkiG9w0BCQEWEXJlbWlAY2hl
-cnJ5cHkub3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBKo554mzIMY+A
-ByUNpaUOP9bJnQ7ZLQe9XgHwoLJR4VzpyZZZR9L4WtImEew05FY3Izerfm3MN3+M
-C0tJ6yQU9sOiU3vBW6RrLIMlfKsnRwBRZ0Knda+O6xldVSosu8Ev3z9VZ94iC/Zg
-KzrH7Mjj/U8/MQO7RBS/LAqee8bFNQIDAQABo4IBBzCCAQMwHQYDVR0OBBYEFDIQ
-2feb71tVZCWpU0qJ/Tw+wdtoMIHTBgNVHSMEgcswgciAFDIQ2feb71tVZCWpU0qJ
-/Tw+wdtooYGkpIGhMIGeMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5p
-YTESMBAGA1UEBxMJU2FuIERpZWdvMRkwFwYDVQQKExBDaGVycnlQeSBQcm9qZWN0
-MREwDwYDVQQLEwhkZXYtdGVzdDEWMBQGA1UEAxMNQ2hlcnJ5UHkgVGVhbTEgMB4G
-CSqGSIb3DQEJARYRcmVtaUBjaGVycnlweS5vcmeCCQCNfAQ+3kMZRjAMBgNVHRME
-BTADAQH/MA0GCSqGSIb3DQEBBAUAA4GBAL7AAQz7IePV48ZTAFHKr88ntPALsL5S
-8vHCZPNMevNkLTj3DYUw2BcnENxMjm1kou2F2BkvheBPNZKIhc6z4hAml3ed1xa2
-D7w6e6OTcstdK/+KrPDDHeOP1dhMWNs2JE1bNlfF1LiXzYKSXpe88eCKjCXsCT/T
-NluCaWQys3MS
------END CERTIFICATE-----
--- a/bundled/cherrypy/cherrypy/test/test.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,551 +0,0 @@
-"""The actual script that runs the entire CP test suite.
-
-There is a library of helper functions for the CherryPy test suite,
-called "helper.py" (in this folder); this module calls that as a library.
-"""
-
-# GREAT CARE has been taken to separate this module from helper.py,
-# because different consumers of each have mutually-exclusive import
-# requirements. So don't go moving functions from here into helper.py,
-# or vice-versa, unless you *really* know what you're doing.
-
-
-import getopt
-from httplib import HTTPSConnection
-import os
-localDir = os.path.dirname(__file__)
-serverpem = os.path.join(os.getcwd(), localDir, 'test.pem')
-import sys
-import warnings
-
-from cherrypy.lib import profiler
-
-
-class TestHarness(object):
-    """A test harness for the CherryPy framework and CherryPy applications."""
-    
-    def __init__(self, supervisor, tests, interactive=True):
-        """Constructor to populate the TestHarness instance.
-        
-        tests should be a list of module names (strings).
-        """
-        self.supervisor = supervisor
-        self.tests = tests
-        self.interactive = interactive
-    
-    def run(self, conf=None):
-        """Run the test harness (using the given [global] conf)."""
-        import cherrypy
-        v = sys.version.split()[0]
-        print("Python version used to run this test script: %s" % v)
-        print("CherryPy version: %s" % cherrypy.__version__)
-        if self.supervisor.scheme == "https":
-            ssl = " (ssl)"
-        else:
-            ssl = ""
-        print("HTTP server version: %s%s" % (self.supervisor.protocol, ssl))
-        print("PID: %s" % os.getpid())
-        print("")
-        
-        cherrypy.server.using_apache = self.supervisor.using_apache
-        cherrypy.server.using_wsgi = self.supervisor.using_wsgi
-        
-        if isinstance(conf, basestring):
-            parser = cherrypy.config._Parser()
-            conf = parser.dict_from_file(conf).get('global', {})
-        else:
-            conf = conf or {}
-        baseconf = conf.copy()
-        baseconf.update({'server.socket_host': self.supervisor.host,
-                         'server.socket_port': self.supervisor.port,
-                         'server.protocol_version': self.supervisor.protocol,
-                         'environment': "test_suite",
-                         })
-        if self.supervisor.scheme == "https":
-            baseconf['server.ssl_certificate'] = serverpem
-            baseconf['server.ssl_private_key'] = serverpem
-        
-        # helper must be imported lazily so the coverage tool
-        # can run against module-level statements within cherrypy.
-        # Also, we have to do "from cherrypy.test import helper",
-        # exactly like each test module does, because a relative import
-        # would stick a second instance of webtest in sys.modules,
-        # and we wouldn't be able to globally override the port anymore.
-        from cherrypy.test import helper, webtest
-        webtest.WebCase.interactive = self.interactive
-        if self.supervisor.scheme == "https":
-            webtest.WebCase.HTTP_CONN = HTTPSConnection
-        print("")
-        print("Running tests: %s" % self.supervisor)
-        
-        return helper.run_test_suite(self.tests, baseconf, self.supervisor)
-
-
-class Supervisor(object):
-    """Base class for modeling and controlling servers during testing."""
-    
-    def __init__(self, **kwargs):
-        for k, v in kwargs.iteritems():
-            setattr(self, k, v)
-
-
-class LocalSupervisor(Supervisor):
-    """Base class for modeling/controlling servers which run in the same process.
-    
-    When the server side runs in a different process, start/stop can dump all
-    state between each test module easily. When the server side runs in the
-    same process as the client, however, we have to do a bit more work to ensure
-    config and mounted apps are reset between tests.
-    """
-    
-    using_apache = False
-    using_wsgi = False
-    
-    def __init__(self, **kwargs):
-        for k, v in kwargs.iteritems():
-            setattr(self, k, v)
-        
-        import cherrypy
-        cherrypy.server.httpserver = self.httpserver_class
-        
-        engine = cherrypy.engine
-        if hasattr(engine, "signal_handler"):
-            engine.signal_handler.subscribe()
-        if hasattr(engine, "console_control_handler"):
-            engine.console_control_handler.subscribe()
-        #engine.subscribe('log', lambda msg, level: sys.stderr.write(msg + os.linesep))
-    
-    def start(self, modulename=None):
-        """Load and start the HTTP server."""
-        import cherrypy
-        
-        if modulename:
-            # Replace the Tree wholesale.
-            cherrypy.tree = cherrypy._cptree.Tree()
-            
-            # Unhook httpserver so cherrypy.server.start() creates a new
-            # one (with config from setup_server, if declared).
-            cherrypy.server.httpserver = None
-            cherrypy.tree = cherrypy._cptree.Tree()
-            
-            if '.' in modulename:
-                package, test_name = modulename.rsplit('.', 1)
-                p = __import__(package, globals(), locals(), fromlist=[test_name])
-                m = getattr(p, test_name)
-            else:
-                m = __import__(modulename, globals(), locals())
-            setup = getattr(m, "setup_server", None)
-            if setup:
-                setup()
-            self.teardown = getattr(m, "teardown_server", None)
-        
-        cherrypy.engine.start()
-        
-        self.sync_apps()
-    
-    def sync_apps(self):
-        """Tell the server about any apps which the setup functions mounted."""
-        pass
-    
-    def stop(self):
-        if self.teardown:
-            self.teardown()
-        import cherrypy
-        cherrypy.engine.exit()
-
-
-class NativeServerSupervisor(LocalSupervisor):
-    """Server supervisor for the builtin HTTP server."""
-    
-    httpserver_class = "cherrypy._cpnative_server.CPHTTPServer"
-    using_apache = False
-    using_wsgi = False
-    
-    def __str__(self):
-        return "Builtin HTTP Server on %s:%s" % (self.host, self.port)
-
-
-class LocalWSGISupervisor(LocalSupervisor):
-    """Server supervisor for the builtin WSGI server."""
-    
-    httpserver_class = "cherrypy._cpwsgi_server.CPWSGIServer"
-    using_apache = False
-    using_wsgi = True
-    
-    def __str__(self):
-        return "Builtin WSGI Server on %s:%s" % (self.host, self.port)
-    
-    def sync_apps(self):
-        """Hook a new WSGI app into the origin server."""
-        import cherrypy
-        cherrypy.server.httpserver.wsgi_app = self.get_app()
-    
-    def get_app(self):
-        """Obtain a new (decorated) WSGI app to hook into the origin server."""
-        import cherrypy
-        app = cherrypy.tree
-        if self.profile:
-            app = profiler.make_app(app, aggregate=False)
-        if self.conquer:
-            try:
-                import wsgiconq
-            except ImportError:
-                warnings.warn("Error importing wsgiconq. pyconquer will not run.")
-            else:
-                app = wsgiconq.WSGILogger(app, c_calls=True)
-        if self.validate:
-            try:
-                from wsgiref import validate
-            except ImportError:
-                warnings.warn("Error importing wsgiref. The validator will not run.")
-            else:
-                app = validate.validator(app)
-        
-        return app
-
-
-def get_cpmodpy_supervisor(**options):
-    from cherrypy.test import modpy
-    sup = modpy.ModPythonSupervisor(**options)
-    sup.template = modpy.conf_cpmodpy
-    return sup
-
-def get_modpygw_supervisor(**options):
-    from cherrypy.test import modpy
-    sup = modpy.ModPythonSupervisor(**options)
-    sup.template = modpy.conf_modpython_gateway
-    sup.using_wsgi = True
-    return sup
-
-def get_modwsgi_supervisor(**options):
-    from cherrypy.test import modwsgi
-    return modwsgi.ModWSGISupervisor(**options)
-
-def get_modfcgid_supervisor(**options):
-    from cherrypy.test import modfcgid
-    return modfcgid.ModFCGISupervisor(**options)
-
-def get_wsgi_u_supervisor(**options):
-    import cherrypy
-    cherrypy.server.wsgi_version = ('u', 0)
-    return LocalWSGISupervisor(**options)
-
-
-class CommandLineParser(object):
-    available_servers = {'wsgi': LocalWSGISupervisor,
-                         'wsgi_u': get_wsgi_u_supervisor,
-                         'native': NativeServerSupervisor,
-                         'cpmodpy': get_cpmodpy_supervisor,
-                         'modpygw': get_modpygw_supervisor,
-                         'modwsgi': get_modwsgi_supervisor,
-                         'modfcgid': get_modfcgid_supervisor,
-                         }
-    default_server = "wsgi"
-    
-    supervisor_factory = None
-    supervisor_options = {
-        'scheme': 'http',
-        'protocol': "HTTP/1.1",
-        'port': 8080,
-        'host': '127.0.0.1',
-        'profile': False,
-        'validate': False,
-        'conquer': False,
-        }
-    
-    cover = False
-    basedir = None
-    interactive = True
-    
-    shortopts = []
-    longopts = ['cover', 'profile', 'validate', 'conquer', 'dumb', '1.0',
-                'ssl', 'help', 'basedir=', 'port=', 'server=', 'host=']
-    
-    def __init__(self, available_tests, args=sys.argv[1:]):
-        """Constructor to populate the TestHarness instance.
-        
-        available_tests should be a list of module names (strings).
-        
-        args defaults to sys.argv[1:], but you can provide a different
-            set of args if you like.
-        """
-        self.available_tests = available_tests
-        self.supervisor_options = self.supervisor_options.copy()
-        
-        longopts = self.longopts[:]
-        longopts.extend(self.available_tests)
-        try:
-            opts, args = getopt.getopt(args, self.shortopts, longopts)
-        except getopt.GetoptError:
-            # print help information and exit
-            self.help()
-            sys.exit(2)
-        
-        self.tests = []
-        
-        for o, a in opts:
-            if o == '--help':
-                self.help()
-                sys.exit()
-            elif o == "--cover":
-                self.cover = True
-            elif o == "--profile":
-                self.supervisor_options['profile'] = True
-            elif o == "--validate":
-                self.supervisor_options['validate'] = True
-            elif o == "--conquer":
-                self.supervisor_options['conquer'] = True
-            elif o == "--dumb":
-                self.interactive = False
-            elif o == "--1.0":
-                self.supervisor_options['protocol'] = "HTTP/1.0"
-            elif o == "--ssl":
-                self.supervisor_options['scheme'] = "https"
-            elif o == "--basedir":
-                self.basedir = a
-            elif o == "--port":
-                self.supervisor_options['port'] = int(a)
-            elif o == "--host":
-                self.supervisor_options['host'] = a
-            elif o == "--server":
-                if a not in self.available_servers:
-                    print('Error: The --server argument must be one of %s.' %
-                          '|'.join(self.available_servers.keys()))
-                    sys.exit(2)
-                self.supervisor_factory = self.available_servers[a]
-            else:
-                o = o[2:]
-                if o in self.available_tests and o not in self.tests:
-                    self.tests.append(o)
-        
-        import cherrypy
-        if self.cover and self.supervisor_options['profile']:
-            # Print error message and exit
-            print('Error: you cannot run the profiler and the '
-                   'coverage tool at the same time.')
-            sys.exit(2)
-        
-        if not self.supervisor_factory:
-            self.supervisor_factory = self.available_servers[self.default_server]
-        
-        if not self.tests:
-            self.tests = self.available_tests[:]
-    
-    def help(self):
-        """Print help for test.py command-line options."""
-        
-        import cherrypy
-        print("""CherryPy Test Program
-    Usage:
-        test.py --help --server=* --host=%s --port=%s --1.0 --ssl --cover
-            --basedir=path --profile --validate --conquer --dumb --tests**
-    """ % (self.__class__.supervisor_options['host'],
-           self.__class__.supervisor_options['port']))
-        print('    * servers:')
-        for name in self.available_servers:
-            if name == self.default_server:
-                print('        --server=%s (default)' % name)
-            else:
-                print('        --server=%s' % name)
-        
-        print("""
-    --host=<name or IP addr>: use a host other than the default (%s).
-        Not yet available with mod_python servers.
-    --port=<int>: use a port other than the default (%s).
-    --1.0: use HTTP/1.0 servers instead of default HTTP/1.1.
-    
-    --cover: turn on code-coverage tool.
-    --basedir=path: display coverage stats for some path other than cherrypy.
-    
-    --profile: turn on WSGI profiling tool.
-    --validate: use wsgiref.validate (builtin in Python 2.5).
-    --conquer: use wsgiconq (which uses pyconquer) to trace calls.
-    --dumb: turn off the interactive output features.
-    """ % (self.__class__.supervisor_options['host'],
-           self.__class__.supervisor_options['port']))
-        
-        print('    ** tests:')
-        for name in self.available_tests:
-            print('        --' + name)
-    
-    def start_coverage(self):
-        """Start the coverage tool.
-        
-        To use this feature, you need to download 'coverage.py',
-        either Gareth Rees' original implementation:
-        http://www.garethrees.org/2001/12/04/python-coverage/
-        
-        or Ned Batchelder's enhanced version:
-        http://www.nedbatchelder.com/code/modules/coverage.html
-        
-        If neither module is found in PYTHONPATH,
-        coverage is silently(!) disabled.
-        """
-        try:
-            from coverage import the_coverage as coverage
-            c = os.path.join(os.path.dirname(__file__), "../lib/coverage.cache")
-            coverage.cache_default = c
-            if c and os.path.exists(c):
-                os.remove(c)
-            coverage.start()
-            import cherrypy
-            from cherrypy.lib import covercp
-            cherrypy.engine.subscribe('start', covercp.start)
-        except ImportError:
-            coverage = None
-        self.coverage = coverage
-    
-    def stop_coverage(self):
-        """Stop the coverage tool, save results, and report."""
-        import cherrypy
-        from cherrypy.lib import covercp
-        cherrypy.engine.unsubscribe('start', covercp.start)
-        if self.coverage:
-            self.coverage.save()
-            self.report_coverage()
-            print("run cherrypy/lib/covercp.py as a script to serve "
-                   "coverage results on port 8080")
-    
-    def report_coverage(self):
-        """Print a summary from the code coverage tool."""
-        
-        import cherrypy
-        basedir = self.basedir
-        if basedir is None:
-            # Assume we want to cover everything in "../../cherrypy/"
-            basedir = os.path.normpath(os.path.join(os.getcwd(), localDir, '../'))
-        else:
-            if not os.path.isabs(basedir):
-                basedir = os.path.normpath(os.path.join(os.getcwd(), basedir))
-        basedir = basedir.lower()
-        
-        self.coverage.get_ready()
-        morfs = [x for x in self.coverage.cexecuted
-                 if x.lower().startswith(basedir)]
-        
-        total_statements = 0
-        total_executed = 0
-        
-        print("")
-        sys.stdout.write("CODE COVERAGE (this might take a while)")
-        for morf in morfs:
-            sys.stdout.write(".")
-            sys.stdout.flush()
-##            name = os.path.split(morf)[1]
-            if morf.find('test') != -1:
-                continue
-            try:
-                _, statements, _, missing, readable  = self.coverage.analysis2(morf)
-                n = len(statements)
-                m = n - len(missing)
-                total_statements = total_statements + n
-                total_executed = total_executed + m
-            except KeyboardInterrupt:
-                raise
-            except:
-                # No, really! We truly want to ignore any other errors.
-                pass
-        
-        pc = 100.0
-        if total_statements > 0:
-            pc = 100.0 * total_executed / total_statements
-        
-        print("\nTotal: %s Covered: %s Percent: %2d%%"
-               % (total_statements, total_executed, pc))
-    
-    def run(self, conf=None):
-        """Run the test harness (using the given [global] conf)."""
-        conf = conf or {}
-        
-        # Start the coverage tool before importing cherrypy,
-        # so module-level global statements are covered.
-        if self.cover:
-            self.start_coverage()
-        
-        supervisor = self.supervisor_factory(**self.supervisor_options)
-        
-        if supervisor.using_apache and 'test_conn' in self.tests:
-            self.tests.remove('test_conn')
-        
-        h = TestHarness(supervisor, self.tests, self.interactive)
-        success = h.run(conf)
-        
-        if self.supervisor_options['profile']:
-            print("")
-            print("run /cherrypy/lib/profiler.py as a script to serve "
-                   "profiling results on port 8080")
-        
-        if self.cover:
-            self.stop_coverage()
-        
-        return success
-
-
-def prefer_parent_path():
-    # Place this __file__'s grandparent (../../) at the start of sys.path,
-    # so that all cherrypy/* imports are from this __file__'s package.
-    curpath = os.path.normpath(os.path.join(os.getcwd(), localDir))
-    grandparent = os.path.normpath(os.path.join(curpath, '../../'))
-    if grandparent not in sys.path:
-        sys.path.insert(0, grandparent)
-
-def run():
-    
-    prefer_parent_path()
-    
-    testList = [
-        'test_auth_basic',
-        'test_auth_digest',
-        'test_bus',
-        'test_proxy',
-        'test_caching',
-        'test_config',
-        'test_conn',
-        'test_core',
-        'test_tools',
-        'test_encoding',
-        'test_etags',
-        'test_http',
-        'test_httpauth',
-        'test_httplib',
-        'test_json',
-        'test_logging',
-        'test_objectmapping',
-        'test_dynamicobjectmapping',
-        'test_misc_tools',
-        'test_request_obj',
-        'test_static',
-        'test_tutorials',
-        'test_virtualhost',
-        'test_mime',
-        'test_session',
-        'test_sessionauthenticate',
-        'test_states',
-        'test_config_server',
-        'test_xmlrpc',
-        'test_wsgiapps',
-        'test_wsgi_ns',
-        'test_wsgi_vhost',
-        
-        # Run refleak test as late as possible to
-        # catch refleaks from all exercised tests.
-        'test_refleaks',
-    ]
-    
-    try:
-        import routes
-        testList.append('test_routes')
-    except ImportError:
-        pass
-    
-    clp = CommandLineParser(testList)
-    success = clp.run()
-    import cherrypy
-    if clp.interactive:
-        print("")
-        raw_input('hit enter')
-    sys.exit(success)
-
-
-if __name__ == '__main__':
-    run()
--- a/bundled/cherrypy/cherrypy/test/test_auth_basic.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-# This file is part of CherryPy <http://www.cherrypy.org/>
-# -*- coding: utf-8 -*-
-# vim:ts=4:sw=4:expandtab:fileencoding=utf-8
-
-from cherrypy.test import test
-test.prefer_parent_path()
-
-try:
-    from hashlib import md5
-except ImportError:
-    # Python 2.4 and earlier
-    from md5 import new as md5
-
-import cherrypy
-from cherrypy.lib import auth_basic
-
-def setup_server():
-    class Root:
-        def index(self):
-            return "This is public."
-        index.exposed = True
-
-    class BasicProtected:
-        def index(self):
-            return "Hello %s, you've been authorized." % cherrypy.request.login
-        index.exposed = True
-
-    class BasicProtected2:
-        def index(self):
-            return "Hello %s, you've been authorized." % cherrypy.request.login
-        index.exposed = True
-
-    userpassdict = {'xuser' : 'xpassword'}
-    userhashdict = {'xuser' : md5('xpassword').hexdigest()}
-
-    def checkpasshash(realm, user, password):
-        p = userhashdict.get(user)
-        return p and p == md5(password).hexdigest() or False
-
-    conf = {'/basic': {'tools.auth_basic.on': True,
-                       'tools.auth_basic.realm': 'wonderland',
-                       'tools.auth_basic.checkpassword': auth_basic.checkpassword_dict(userpassdict)},
-            '/basic2': {'tools.auth_basic.on': True,
-                        'tools.auth_basic.realm': 'wonderland',
-                        'tools.auth_basic.checkpassword': checkpasshash},
-           }
-
-    root = Root()
-    root.basic = BasicProtected()
-    root.basic2 = BasicProtected2()
-    cherrypy.tree.mount(root, config=conf)
-
-from cherrypy.test import helper
-
-class BasicAuthTest(helper.CPWebCase):
-
-    def testPublic(self):
-        self.getPage("/")
-        self.assertStatus('200 OK')
-        self.assertHeader('Content-Type', 'text/html;charset=utf-8')
-        self.assertBody('This is public.')
-
-    def testBasic(self):
-        self.getPage("/basic/")
-        self.assertStatus(401)
-        self.assertHeader('WWW-Authenticate', 'Basic realm="wonderland"')
-
-        self.getPage('/basic/', [('Authorization', 'Basic eHVzZXI6eHBhc3N3b3JX')])
-        self.assertStatus(401)
-
-        self.getPage('/basic/', [('Authorization', 'Basic eHVzZXI6eHBhc3N3b3Jk')])
-        self.assertStatus('200 OK')
-        self.assertBody("Hello xuser, you've been authorized.")
-
-    def testBasic2(self):
-        self.getPage("/basic2/")
-        self.assertStatus(401)
-        self.assertHeader('WWW-Authenticate', 'Basic realm="wonderland"')
-
-        self.getPage('/basic2/', [('Authorization', 'Basic eHVzZXI6eHBhc3N3b3JX')])
-        self.assertStatus(401)
-
-        self.getPage('/basic2/', [('Authorization', 'Basic eHVzZXI6eHBhc3N3b3Jk')])
-        self.assertStatus('200 OK')
-        self.assertBody("Hello xuser, you've been authorized.")
-
-
-if __name__ == "__main__":
-    helper.testmain()
--- a/bundled/cherrypy/cherrypy/test/test_auth_digest.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,120 +0,0 @@
-# This file is part of CherryPy <http://www.cherrypy.org/>
-# -*- coding: utf-8 -*-
-# vim:ts=4:sw=4:expandtab:fileencoding=utf-8
-
-from cherrypy.test import test
-test.prefer_parent_path()
-
-
-import cherrypy
-from cherrypy.lib import auth_digest
-
-def setup_server():
-    class Root:
-        def index(self):
-            return "This is public."
-        index.exposed = True
-
-    class DigestProtected:
-        def index(self):
-            return "Hello %s, you've been authorized." % cherrypy.request.login
-        index.exposed = True
-
-    def fetch_users():
-        return {'test': 'test'}
-
-
-    get_ha1 = cherrypy.lib.auth_digest.get_ha1_dict_plain(fetch_users())
-    conf = {'/digest': {'tools.auth_digest.on': True,
-                        'tools.auth_digest.realm': 'localhost',
-                        'tools.auth_digest.get_ha1': get_ha1,
-                        'tools.auth_digest.key': 'a565c27146791cfb',
-                        'tools.auth_digest.debug': 'True'}}
-
-    root = Root()
-    root.digest = DigestProtected()
-    cherrypy.tree.mount(root, config=conf)
-
-from cherrypy.test import helper
-
-class DigestAuthTest(helper.CPWebCase):
-
-    def testPublic(self):
-        self.getPage("/")
-        self.assertStatus('200 OK')
-        self.assertHeader('Content-Type', 'text/html;charset=utf-8')
-        self.assertBody('This is public.')
-
-    def testDigest(self):
-        self.getPage("/digest/")
-        self.assertStatus(401)
-
-        value = None
-        for k, v in self.headers:
-            if k.lower() == "www-authenticate":
-                if v.startswith("Digest"):
-                    value = v
-                    break
-
-        if value is None:
-            self._handlewebError("Digest authentification scheme was not found")
-
-        value = value[7:]
-        items = value.split(', ')
-        tokens = {}
-        for item in items:
-            key, value = item.split('=')
-            tokens[key.lower()] = value
-
-        missing_msg = "%s is missing"
-        bad_value_msg = "'%s' was expecting '%s' but found '%s'"
-        nonce = None
-        if 'realm' not in tokens:
-            self._handlewebError(missing_msg % 'realm')
-        elif tokens['realm'] != '"localhost"':
-            self._handlewebError(bad_value_msg % ('realm', '"localhost"', tokens['realm']))
-        if 'nonce' not in tokens:
-            self._handlewebError(missing_msg % 'nonce')
-        else:
-            nonce = tokens['nonce'].strip('"')
-        if 'algorithm' not in tokens:
-            self._handlewebError(missing_msg % 'algorithm')
-        elif tokens['algorithm'] != '"MD5"':
-            self._handlewebError(bad_value_msg % ('algorithm', '"MD5"', tokens['algorithm']))
-        if 'qop' not in tokens:
-            self._handlewebError(missing_msg % 'qop')
-        elif tokens['qop'] != '"auth"':
-            self._handlewebError(bad_value_msg % ('qop', '"auth"', tokens['qop']))
-
-        get_ha1 = auth_digest.get_ha1_dict_plain({'test' : 'test'})
-
-        # Test user agent response with a wrong value for 'realm'
-        base_auth = 'Digest username="test", realm="wrong realm", nonce="%s", uri="/digest/", algorithm=MD5, response="%s", qop=auth, nc=%s, cnonce="1522e61005789929"'
-
-        auth_header = base_auth % (nonce, '11111111111111111111111111111111', '00000001')
-        auth = auth_digest.HttpDigestAuthorization(auth_header, 'GET')
-        # calculate the response digest
-        ha1 = get_ha1(auth.realm, 'test')
-        response = auth.request_digest(ha1)
-        # send response with correct response digest, but wrong realm
-        auth_header = base_auth % (nonce, response, '00000001')
-        self.getPage('/digest/', [('Authorization', auth_header)])
-        self.assertStatus(401)
-
-        # Test that must pass
-        base_auth = 'Digest username="test", realm="localhost", nonce="%s", uri="/digest/", algorithm=MD5, response="%s", qop=auth, nc=%s, cnonce="1522e61005789929"'
-
-        auth_header = base_auth % (nonce, '11111111111111111111111111111111', '00000001')
-        auth = auth_digest.HttpDigestAuthorization(auth_header, 'GET')
-        # calculate the response digest
-        ha1 = get_ha1('localhost', 'test')
-        response = auth.request_digest(ha1)
-        # send response with correct response digest
-        auth_header = base_auth % (nonce, response, '00000001')
-        self.getPage('/digest/', [('Authorization', auth_header)])
-        self.assertStatus('200 OK')
-        self.assertBody("Hello test, you've been authorized.")
-
-if __name__ == "__main__":
-    helper.testmain()
-
--- a/bundled/cherrypy/cherrypy/test/test_bus.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,265 +0,0 @@
-from cherrypy.test import test
-test.prefer_parent_path()
-
-try:
-    set
-except NameError:
-    from sets import Set as set
-import threading
-import time
-import unittest
-
-import cherrypy
-from cherrypy.process import wspbus
-
-
-msg = "Listener %d on channel %s: %s."
-
-
-class PublishSubscribeTests(unittest.TestCase):
-
-    def get_listener(self, channel, index):
-        def listener(arg=None):
-            self.responses.append(msg % (index, channel, arg))
-        return listener
-    
-    def test_builtin_channels(self):
-        b = wspbus.Bus()
-        
-        self.responses, expected = [], []
-        
-        for channel in b.listeners:
-            for index, priority in enumerate([100, 50, 0, 51]):
-                b.subscribe(channel, self.get_listener(channel, index), priority)
-        
-        for channel in b.listeners:
-            b.publish(channel)
-            expected.extend([msg % (i, channel, None) for i in (2, 1, 3, 0)])
-            b.publish(channel, arg=79347)
-            expected.extend([msg % (i, channel, 79347) for i in (2, 1, 3, 0)])
-        
-        self.assertEqual(self.responses, expected)
-    
-    def test_custom_channels(self):
-        b = wspbus.Bus()
-        
-        self.responses, expected = [], []
-        
-        custom_listeners = ('hugh', 'louis', 'dewey')
-        for channel in custom_listeners:
-            for index, priority in enumerate([None, 10, 60, 40]):
-                b.subscribe(channel, self.get_listener(channel, index), priority)
-        
-        for channel in custom_listeners:
-            b.publish(channel, 'ah so')
-            expected.extend([msg % (i, channel, 'ah so') for i in (1, 3, 0, 2)])
-            b.publish(channel)
-            expected.extend([msg % (i, channel, None) for i in (1, 3, 0, 2)])
-        
-        self.assertEqual(self.responses, expected)
-    
-    def test_listener_errors(self):
-        b = wspbus.Bus()
-        
-        self.responses, expected = [], []
-        channels = [c for c in b.listeners if c != 'log']
-        
-        for channel in channels:
-            b.subscribe(channel, self.get_listener(channel, 1))
-            # This will break since the lambda takes no args.
-            b.subscribe(channel, lambda: None, priority=20)
-        
-        for channel in channels:
-            self.assertRaises(wspbus.ChannelFailures, b.publish, channel, 123)
-            expected.append(msg % (1, channel, 123))
-        
-        self.assertEqual(self.responses, expected)
-
-
-class BusMethodTests(unittest.TestCase):
-    
-    def log(self, bus):
-        self._log_entries = []
-        def logit(msg, level):
-            self._log_entries.append(msg)
-        bus.subscribe('log', logit)
-    
-    def assertLog(self, entries):
-        self.assertEqual(self._log_entries, entries)
-    
-    def get_listener(self, channel, index):
-        def listener(arg=None):
-            self.responses.append(msg % (index, channel, arg))
-        return listener
-    
-    def test_start(self):
-        b = wspbus.Bus()
-        self.log(b)
-        
-        self.responses = []
-        num = 3
-        for index in range(num):
-            b.subscribe('start', self.get_listener('start', index))
-        
-        b.start()
-        try:
-            # The start method MUST call all 'start' listeners.
-            self.assertEqual(set(self.responses),
-                             set([msg % (i, 'start', None) for i in range(num)]))
-            # The start method MUST move the state to STARTED
-            # (or EXITING, if errors occur)
-            self.assertEqual(b.state, b.states.STARTED)
-            # The start method MUST log its states.
-            self.assertLog(['Bus STARTING', 'Bus STARTED'])
-        finally:
-            # Exit so the atexit handler doesn't complain.
-            b.exit()
-    
-    def test_stop(self):
-        b = wspbus.Bus()
-        self.log(b)
-        
-        self.responses = []
-        num = 3
-        for index in range(num):
-            b.subscribe('stop', self.get_listener('stop', index))
-        
-        b.stop()
-        
-        # The stop method MUST call all 'stop' listeners.
-        self.assertEqual(set(self.responses),
-                         set([msg % (i, 'stop', None) for i in range(num)]))
-        # The stop method MUST move the state to STOPPED
-        self.assertEqual(b.state, b.states.STOPPED)
-        # The stop method MUST log its states.
-        self.assertLog(['Bus STOPPING', 'Bus STOPPED'])
-    
-    def test_graceful(self):
-        b = wspbus.Bus()
-        self.log(b)
-        
-        self.responses = []
-        num = 3
-        for index in range(num):
-            b.subscribe('graceful', self.get_listener('graceful', index))
-        
-        b.graceful()
-        
-        # The graceful method MUST call all 'graceful' listeners.
-        self.assertEqual(set(self.responses),
-                         set([msg % (i, 'graceful', None) for i in range(num)]))
-        # The graceful method MUST log its states.
-        self.assertLog(['Bus graceful'])
-    
-    def test_exit(self):
-        b = wspbus.Bus()
-        self.log(b)
-        
-        self.responses = []
-        num = 3
-        for index in range(num):
-            b.subscribe('stop', self.get_listener('stop', index))
-            b.subscribe('exit', self.get_listener('exit', index))
-        
-        b.exit()
-        
-        # The exit method MUST call all 'stop' listeners,
-        # and then all 'exit' listeners.
-        self.assertEqual(set(self.responses),
-                         set([msg % (i, 'stop', None) for i in range(num)] +
-                             [msg % (i, 'exit', None) for i in range(num)]))
-        # The exit method MUST move the state to EXITING
-        self.assertEqual(b.state, b.states.EXITING)
-        # The exit method MUST log its states.
-        self.assertLog(['Bus STOPPING', 'Bus STOPPED', 'Bus EXITING', 'Bus EXITED'])
-    
-    def test_wait(self):
-        b = wspbus.Bus()
-        
-        def f(method):
-            time.sleep(0.2)
-            getattr(b, method)()
-        
-        for method, states in [('start', [b.states.STARTED]),
-                               ('stop', [b.states.STOPPED]),
-                               ('start', [b.states.STARTING, b.states.STARTED]),
-                               ('exit', [b.states.EXITING]),
-                               ]:
-            threading.Thread(target=f, args=(method,)).start()
-            b.wait(states)
-            
-            # The wait method MUST wait for the given state(s).
-            if b.state not in states:
-                self.fail("State %r not in %r" % (b.state, states))
-    
-    def test_block(self):
-        b = wspbus.Bus()
-        self.log(b)
-        
-        def f():
-            time.sleep(0.2)
-            b.exit()
-        def g():
-            time.sleep(0.4)
-        threading.Thread(target=f).start()
-        threading.Thread(target=g).start()
-        self.assertEqual(len(threading.enumerate()), 3)
-        
-        b.block()
-        
-        # The block method MUST wait for the EXITING state.
-        self.assertEqual(b.state, b.states.EXITING)
-        # The block method MUST wait for ALL non-main threads to finish.
-        self.assertEqual(len(threading.enumerate()), 1)
-        self.assertLog(['Bus STOPPING', 'Bus STOPPED',
-                        'Bus EXITING', 'Bus EXITED',
-                        'Waiting for child threads to terminate...'])
-    
-    def test_start_with_callback(self):
-        b = wspbus.Bus()
-        self.log(b)
-        try:
-            events = []
-            def f(*args, **kwargs):
-                events.append(("f", args, kwargs))
-            def g():
-                events.append("g")
-            b.subscribe("start", g)
-            b.start_with_callback(f, (1, 3, 5), {"foo": "bar"})
-            # Give wait() time to run f()
-            time.sleep(0.2)
-            
-            # The callback method MUST wait for the STARTED state.
-            self.assertEqual(b.state, b.states.STARTED)
-            # The callback method MUST run after all start methods.
-            self.assertEqual(events, ["g", ("f", (1, 3, 5), {"foo": "bar"})])
-        finally:
-            b.exit()
-    
-    def test_log(self):
-        b = wspbus.Bus()
-        self.log(b)
-        self.assertLog([])
-        
-        # Try a normal message.
-        expected = []
-        for msg in ["O mah darlin'"] * 3 + ["Clementiiiiiiiine"]:
-            b.log(msg)
-            expected.append(msg)
-            self.assertLog(expected)
-        
-        # Try an error message
-        try:
-            foo
-        except NameError:
-            b.log("You are lost and gone forever", traceback=True)
-            lastmsg = self._log_entries[-1]
-            if "Traceback" not in lastmsg or "NameError" not in lastmsg:
-                self.fail("Last log message %r did not contain "
-                          "the expected traceback." % lastmsg)
-        else:
-            self.fail("NameError was not raised as expected.")
-
-
-if __name__ == "__main__":
-    unittest.main()
--- a/bundled/cherrypy/cherrypy/test/test_caching.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,335 +0,0 @@
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import datetime
-import gzip
-from itertools import count
-import os
-curdir = os.path.join(os.getcwd(), os.path.dirname(__file__))
-import sys
-import threading
-import time
-import urllib
-
-import cherrypy
-from cherrypy.lib import httputil
-
-gif_bytes = ('GIF89a\x01\x00\x01\x00\x82\x00\x01\x99"\x1e\x00\x00\x00\x00\x00'
-             '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
-             '\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x02\x03\x02\x08\t\x00;')
-
-
-def setup_server():
-    
-    class Root:
-        
-        _cp_config = {'tools.caching.on': True}
-        
-        def __init__(self):
-            self.counter = 0
-            self.control_counter = 0
-            self.longlock = threading.Lock()
-        
-        def index(self):
-            self.counter += 1
-            msg = "visit #%s" % self.counter
-            return msg
-        index.exposed = True
-        
-        def control(self):
-            self.control_counter += 1
-            return "visit #%s" % self.control_counter
-        control.exposed = True
-        
-        def a_gif(self):
-            cherrypy.response.headers['Last-Modified'] = httputil.HTTPDate()
-            return gif_bytes
-        a_gif.exposed = True
-        
-        def long_process(self, seconds='1'):
-            try:
-                self.longlock.acquire()
-                time.sleep(float(seconds))
-            finally:
-                self.longlock.release()
-            return 'success!'
-        long_process.exposed = True
-        
-        def clear_cache(self, path):
-            cherrypy._cache.store[cherrypy.request.base + path].clear()
-        clear_cache.exposed = True
-    
-    class VaryHeaderCachingServer(object):
-        
-        _cp_config = {'tools.caching.on': True,
-            'tools.response_headers.on': True,
-            'tools.response_headers.headers': [('Vary', 'Our-Varying-Header')],
-            }
-        
-        def __init__(self):
-            self.counter = count(1)
-        
-        def index(self):
-            return "visit #%s" % self.counter.next()
-        index.exposed = True
-    
-    class UnCached(object):
-        _cp_config = {'tools.expires.on': True,
-                      'tools.expires.secs': 60,
-                      'tools.staticdir.on': True,
-                      'tools.staticdir.dir': 'static',
-                      'tools.staticdir.root': curdir,
-                      }
-
-        def force(self):
-            cherrypy.response.headers['Etag'] = 'bibbitybobbityboo'
-            self._cp_config['tools.expires.force'] = True
-            self._cp_config['tools.expires.secs'] = 0
-            return "being forceful"
-        force.exposed = True
-        force._cp_config = {'tools.expires.secs': 0}
-
-        def dynamic(self):
-            cherrypy.response.headers['Etag'] = 'bibbitybobbityboo'
-            cherrypy.response.headers['Cache-Control'] = 'private'
-            return "D-d-d-dynamic!"
-        dynamic.exposed = True
-
-        def cacheable(self):
-            cherrypy.response.headers['Etag'] = 'bibbitybobbityboo'
-            return "Hi, I'm cacheable."
-        cacheable.exposed = True
-
-        def specific(self):
-            cherrypy.response.headers['Etag'] = 'need_this_to_make_me_cacheable'
-            return "I am being specific"
-        specific.exposed = True
-        specific._cp_config = {'tools.expires.secs': 86400}
-
-        class Foo(object):pass
-        
-        def wrongtype(self):
-            cherrypy.response.headers['Etag'] = 'need_this_to_make_me_cacheable'
-            return "Woops"
-        wrongtype.exposed = True
-        wrongtype._cp_config = {'tools.expires.secs': Foo()}
-    
-    cherrypy.tree.mount(Root())
-    cherrypy.tree.mount(UnCached(), "/expires")
-    cherrypy.tree.mount(VaryHeaderCachingServer(), "/varying_headers")
-    cherrypy.config.update({'tools.gzip.on': True})
-
-
-from cherrypy.test import helper
-
-class CacheTest(helper.CPWebCase):
-
-    def testCaching(self):
-        elapsed = 0.0
-        for trial in range(10):
-            self.getPage("/")
-            # The response should be the same every time,
-            # except for the Age response header.
-            self.assertBody('visit #1')
-            if trial != 0:
-                age = int(self.assertHeader("Age"))
-                self.assert_(age >= elapsed)
-                elapsed = age
-        
-        # POST, PUT, DELETE should not be cached.
-        self.getPage("/", method="POST")
-        self.assertBody('visit #2')
-        # Because gzip is turned on, the Vary header should always Vary for content-encoding
-        self.assertHeader('Vary', 'Accept-Encoding')
-        # The previous request should have invalidated the cache,
-        # so this request will recalc the response.
-        self.getPage("/", method="GET")
-        self.assertBody('visit #3')
-        # ...but this request should get the cached copy.
-        self.getPage("/", method="GET")
-        self.assertBody('visit #3')
-        self.getPage("/", method="DELETE")
-        self.assertBody('visit #4')
-        
-        # The previous request should have invalidated the cache,
-        # so this request will recalc the response.
-        self.getPage("/", method="GET", headers=[('Accept-Encoding', 'gzip')])
-        self.assertHeader('Content-Encoding', 'gzip')
-        self.assertHeader('Vary')
-        self.assertEqual(cherrypy.lib.encoding.decompress(self.body), "visit #5")
-        
-        # Now check that a second request gets the gzip header and gzipped body
-        # This also tests a bug in 3.0 to 3.0.2 whereby the cached, gzipped
-        # response body was being gzipped a second time.
-        self.getPage("/", method="GET", headers=[('Accept-Encoding', 'gzip')])
-        self.assertHeader('Content-Encoding', 'gzip')
-        self.assertEqual(cherrypy.lib.encoding.decompress(self.body), "visit #5")
-        
-        # Now check that a third request that doesn't accept gzip
-        # skips the cache (because the 'Vary' header denies it).
-        self.getPage("/", method="GET")
-        self.assertNoHeader('Content-Encoding')
-        self.assertBody('visit #6')
-    
-    def testVaryHeader(self):
-        self.getPage("/varying_headers/")
-        self.assertStatus("200 OK")
-        self.assertHeaderItemValue('Vary', 'Our-Varying-Header')
-        self.assertBody('visit #1')
-        
-        # Now check that different 'Vary'-fields don't evict each other.
-        # This test creates 2 requests with different 'Our-Varying-Header'
-        # and then tests if the first one still exists.
-        self.getPage("/varying_headers/", headers=[('Our-Varying-Header', 'request 2')])
-        self.assertStatus("200 OK")
-        self.assertBody('visit #2')
-        
-        self.getPage("/varying_headers/", headers=[('Our-Varying-Header', 'request 2')])
-        self.assertStatus("200 OK")
-        self.assertBody('visit #2')
-        
-        self.getPage("/varying_headers/")
-        self.assertStatus("200 OK")
-        self.assertBody('visit #1')
-        
-    def testExpiresTool(self):
-        # test setting an expires header
-        self.getPage("/expires/specific")
-        self.assertStatus("200 OK")
-        self.assertHeader("Expires")
-        
-        # test exceptions for bad time values
-        self.getPage("/expires/wrongtype")
-        self.assertStatus(500)
-        self.assertInBody("TypeError")
-        
-        # static content should not have "cache prevention" headers
-        self.getPage("/expires/index.html")
-        self.assertStatus("200 OK")
-        self.assertNoHeader("Pragma")
-        self.assertNoHeader("Cache-Control")
-        self.assertHeader("Expires")
-        
-        # dynamic content that sets indicators should not have
-        # "cache prevention" headers
-        self.getPage("/expires/cacheable")
-        self.assertStatus("200 OK")
-        self.assertNoHeader("Pragma")
-        self.assertNoHeader("Cache-Control")
-        self.assertHeader("Expires")
-        
-        self.getPage('/expires/dynamic')
-        self.assertBody("D-d-d-dynamic!")
-        # the Cache-Control header should be untouched
-        self.assertHeader("Cache-Control", "private")
-        self.assertHeader("Expires")
-        
-        # configure the tool to ignore indicators and replace existing headers
-        self.getPage("/expires/force")
-        self.assertStatus("200 OK")
-        # This also gives us a chance to test 0 expiry with no other headers
-        self.assertHeader("Pragma", "no-cache")
-        if cherrypy.server.protocol_version == "HTTP/1.1":
-            self.assertHeader("Cache-Control", "no-cache, must-revalidate")
-        self.assertHeader("Expires", "Sun, 28 Jan 2007 00:00:00 GMT")
-        
-        # static content should now have "cache prevention" headers
-        self.getPage("/expires/index.html")
-        self.assertStatus("200 OK")
-        self.assertHeader("Pragma", "no-cache")
-        if cherrypy.server.protocol_version == "HTTP/1.1":
-            self.assertHeader("Cache-Control", "no-cache, must-revalidate")
-        self.assertHeader("Expires", "Sun, 28 Jan 2007 00:00:00 GMT")
-        
-        # the cacheable handler should now have "cache prevention" headers
-        self.getPage("/expires/cacheable")
-        self.assertStatus("200 OK")
-        self.assertHeader("Pragma", "no-cache")
-        if cherrypy.server.protocol_version == "HTTP/1.1":
-            self.assertHeader("Cache-Control", "no-cache, must-revalidate")
-        self.assertHeader("Expires", "Sun, 28 Jan 2007 00:00:00 GMT")
-        
-        self.getPage('/expires/dynamic')
-        self.assertBody("D-d-d-dynamic!")
-        # dynamic sets Cache-Control to private but it should  be
-        # overwritten here ...
-        self.assertHeader("Pragma", "no-cache")
-        if cherrypy.server.protocol_version == "HTTP/1.1":
-            self.assertHeader("Cache-Control", "no-cache, must-revalidate")
-        self.assertHeader("Expires", "Sun, 28 Jan 2007 00:00:00 GMT")
-    
-    def testLastModified(self):
-        self.getPage("/a.gif")
-        self.assertStatus(200)
-        self.assertBody(gif_bytes)
-        lm1 = self.assertHeader("Last-Modified")
-        
-        # this request should get the cached copy.
-        self.getPage("/a.gif")
-        self.assertStatus(200)
-        self.assertBody(gif_bytes)
-        self.assertHeader("Age")
-        lm2 = self.assertHeader("Last-Modified")
-        self.assertEqual(lm1, lm2)
-        
-        # this request should match the cached copy, but raise 304.
-        self.getPage("/a.gif", [('If-Modified-Since', lm1)])
-        self.assertStatus(304)
-        self.assertNoHeader("Last-Modified")
-        if not getattr(cherrypy.server, "using_apache", False):
-            self.assertHeader("Age")
-    
-    def test_antistampede(self):
-        SECONDS = 4
-        # We MUST make an initial synchronous request in order to create the
-        # AntiStampedeCache object, and populate its selecting_headers,
-        # before the actual stampede.
-        self.getPage("/long_process?seconds=%d" % SECONDS)
-        self.assertBody('success!')
-        self.getPage("/clear_cache?path=" +
-            urllib.quote('/long_process?seconds=%d' % SECONDS, safe=''))
-        self.assertStatus(200)
-        sys.stdout.write("prepped... ")
-        sys.stdout.flush()
-        
-        start = datetime.datetime.now()
-        def run():
-            self.getPage("/long_process?seconds=%d" % SECONDS)
-            # The response should be the same every time
-            self.assertBody('success!')
-        ts = [threading.Thread(target=run) for i in xrange(100)]
-        for t in ts:
-            t.start()
-        for t in ts:
-            t.join()
-        self.assertEqualDates(start, datetime.datetime.now(),
-                              # Allow a second for our thread/TCP overhead etc.
-                              seconds=SECONDS + 1)
-    
-    def test_cache_control(self):
-        self.getPage("/control")
-        self.assertBody('visit #1')
-        self.getPage("/control")
-        self.assertBody('visit #1')
-        
-        self.getPage("/control", headers=[('Cache-Control', 'no-cache')])
-        self.assertBody('visit #2')
-        self.getPage("/control")
-        self.assertBody('visit #2')
-        
-        self.getPage("/control", headers=[('Pragma', 'no-cache')])
-        self.assertBody('visit #3')
-        self.getPage("/control")
-        self.assertBody('visit #3')
-        
-        time.sleep(1)
-        self.getPage("/control", headers=[('Cache-Control', 'max-age=0')])
-        self.assertBody('visit #4')
-        self.getPage("/control")
-        self.assertBody('visit #4')
-
-
-
-if __name__ == '__main__':
-    helper.testmain()
-
--- a/bundled/cherrypy/cherrypy/test/test_config.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,255 +0,0 @@
-"""Tests for the CherryPy configuration system."""
-
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import os, sys
-localDir = os.path.join(os.getcwd(), os.path.dirname(__file__))
-
-try:
-    from cStringIO import StringIO
-except ImportError:
-    from StringIO import StringIO
-import unittest
-
-import cherrypy
-
-def setup_server():
-    
-    class Root:
-        
-        _cp_config = {'foo': 'this',
-                      'bar': 'that'}
-        
-        def __init__(self):
-            cherrypy.config.namespaces['db'] = self.db_namespace
-        
-        def db_namespace(self, k, v):
-            if k == "scheme":
-                self.db = v
-        
-        # @cherrypy.expose(alias=('global_', 'xyz'))
-        def index(self, key):
-            return cherrypy.request.config.get(key, "None")
-        index = cherrypy.expose(index, alias=('global_', 'xyz'))
-        
-        def repr(self, key):
-            return repr(cherrypy.request.config.get(key, None))
-        repr.exposed = True
-        
-        def dbscheme(self):
-            return self.db
-        dbscheme.exposed = True
-        
-        def plain(self, x):
-            return x
-        plain.exposed = True
-        plain._cp_config = {'request.body.attempt_charsets': ['utf-16']}
-        
-        favicon_ico = cherrypy.tools.staticfile.handler(
-                        filename=os.path.join(localDir, '../favicon.ico'))
-    
-    class Foo:
-        
-        _cp_config = {'foo': 'this2',
-                      'baz': 'that2'}
-        
-        def index(self, key):
-            return cherrypy.request.config.get(key, "None")
-        index.exposed = True
-        nex = index
-        
-        def silly(self):
-            return 'Hello world'
-        silly.exposed = True
-        silly._cp_config = {'response.headers.X-silly': 'sillyval'}
-            
-        def bar(self, key):
-            return repr(cherrypy.request.config.get(key, None))
-        bar.exposed = True
-        bar._cp_config = {'foo': 'this3', 'bax': 'this4'}
-    
-    class Another:
-        
-        def index(self, key):
-            return str(cherrypy.request.config.get(key, "None"))
-        index.exposed = True
-    
-    
-    def raw_namespace(key, value):
-        if key == 'input.map':
-            handler = cherrypy.request.handler
-            def wrapper():
-                params = cherrypy.request.params
-                for name, coercer in list(value.items()):
-                    try:
-                        params[name] = coercer(params[name])
-                    except KeyError:
-                        pass
-                return handler()
-            cherrypy.request.handler = wrapper
-        elif key == 'output':
-            handler = cherrypy.request.handler
-            def wrapper():
-                # 'value' is a type (like int or str).
-                return value(handler())
-            cherrypy.request.handler = wrapper
-    
-    class Raw:
-        
-        _cp_config = {'raw.output': repr}
-        
-        def incr(self, num):
-            return num + 1
-        incr.exposed = True
-        incr._cp_config = {'raw.input.map': {'num': int}}
-    
-    ioconf = StringIO("""
-[/]
-neg: -1234
-filename: os.path.join(sys.prefix, "hello.py")
-thing1: cherrypy.lib.httputil.response_codes[404]
-thing2: __import__('cherrypy.tutorial', globals(), locals(), ['']).thing2
-complex: 3+2j
-ones: "11"
-twos: "22"
-stradd: %%(ones)s + %%(twos)s + "33"
-
-[/favicon.ico]
-tools.staticfile.filename = %r
-""" % os.path.join(localDir, 'static/dirback.jpg'))
-    
-    root = Root()
-    root.foo = Foo()
-    root.raw = Raw()
-    app = cherrypy.tree.mount(root, config=ioconf)
-    app.request_class.namespaces['raw'] = raw_namespace
-    
-    cherrypy.tree.mount(Another(), "/another")
-    cherrypy.config.update({'luxuryyacht': 'throatwobblermangrove',
-                            'db.scheme': r"sqlite///memory",
-                            })
-
-
-#                             Client-side code                             #
-
-from cherrypy.test import helper
-
-class ConfigTests(helper.CPWebCase):
-    
-    def testConfig(self):
-        tests = [
-            ('/',        'nex', 'None'),
-            ('/',        'foo', 'this'),
-            ('/',        'bar', 'that'),
-            ('/xyz',     'foo', 'this'),
-            ('/foo/',    'foo', 'this2'),
-            ('/foo/',    'bar', 'that'),
-            ('/foo/',    'bax', 'None'),
-            ('/foo/bar', 'baz', "'that2'"),
-            ('/foo/nex', 'baz', 'that2'),
-            # If 'foo' == 'this', then the mount point '/another' leaks into '/'.
-            ('/another/','foo', 'None'),
-        ]
-        for path, key, expected in tests:
-            self.getPage(path + "?key=" + key)
-            self.assertBody(expected)
-        
-        expectedconf = {
-            # From CP defaults
-            'tools.log_headers.on': False,
-            'tools.log_tracebacks.on': True,
-            'request.show_tracebacks': True,
-            'log.screen': False,
-            'environment': 'test_suite',
-            'engine.autoreload_on': False,
-            # From global config
-            'luxuryyacht': 'throatwobblermangrove',
-            # From Root._cp_config
-            'bar': 'that',
-            # From Foo._cp_config
-            'baz': 'that2',
-            # From Foo.bar._cp_config
-            'foo': 'this3',
-            'bax': 'this4',
-            }
-        for key, expected in expectedconf.items():
-            self.getPage("/foo/bar?key=" + key)
-            self.assertBody(repr(expected))
-    
-    def testUnrepr(self):
-        self.getPage("/repr?key=neg")
-        self.assertBody("-1234")
-        
-        self.getPage("/repr?key=filename")
-        self.assertBody(repr(os.path.join(sys.prefix, "hello.py")))
-        
-        self.getPage("/repr?key=thing1")
-        self.assertBody(repr(cherrypy.lib.httputil.response_codes[404]))
-        
-        if not getattr(cherrypy.server, "using_apache", False):
-            # The object ID's won't match up when using Apache, since the
-            # server and client are running in different processes.
-            self.getPage("/repr?key=thing2")
-            from cherrypy.tutorial import thing2
-            self.assertBody(repr(thing2))
-        
-        self.getPage("/repr?key=complex")
-        self.assertBody("(3+2j)")
-        
-        self.getPage("/repr?key=stradd")
-        self.assertBody(repr("112233"))
-
-    def testRespNamespaces(self):
-        self.getPage("/foo/silly")
-        self.assertHeader('X-silly', 'sillyval')
-        self.assertBody('Hello world')
-    
-    def testCustomNamespaces(self):
-        self.getPage("/raw/incr?num=12")
-        self.assertBody("13")
-        
-        self.getPage("/dbscheme")
-        self.assertBody(r"sqlite///memory")
-    
-    def testHandlerToolConfigOverride(self):
-        # Assert that config overrides tool constructor args. Above, we set
-        # the favicon in the page handler to be '../favicon.ico',
-        # but then overrode it in config to be './static/dirback.jpg'.
-        self.getPage("/favicon.ico")
-        self.assertBody(open(os.path.join(localDir, "static/dirback.jpg"),
-                             "rb").read())
-    
-    def test_request_body_namespace(self):
-        self.getPage("/plain", method='POST', headers=[
-            ('Content-Type', 'application/x-www-form-urlencoded'),
-            ('Content-Length', '13')],
-            body='\xff\xfex\x00=\xff\xfea\x00b\x00c\x00')
-        self.assertBody("abc")
-
-
-class VariableSubstitutionTests(unittest.TestCase):
-    
-    def test_config(self):
-        from textwrap import dedent
-    
-        # variable substitution with [DEFAULT]
-        conf = dedent("""
-        [DEFAULT]
-        dir = "/some/dir"
-        my.dir = %(dir)s + "/sub"
-
-        [my]
-        my.dir = %(dir)s + "/my/dir"
-        my.dir2 = %(my.dir)s + '/dir2'
-
-        """)
-
-        fp = StringIO(conf)
-
-        cherrypy.config.update(fp)
-        self.assertEqual(cherrypy.config["my"]["my.dir"], "/some/dir/my/dir")
-        self.assertEqual(cherrypy.config["my"]["my.dir2"], "/some/dir/my/dir/dir2")
-
-if __name__ == '__main__':
-    helper.testmain()
--- a/bundled/cherrypy/cherrypy/test/test_config_server.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,127 +0,0 @@
-"""Tests for the CherryPy configuration system."""
-
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import os, sys
-localDir = os.path.join(os.getcwd(), os.path.dirname(__file__))
-import socket
-import time
-
-import cherrypy
-
-def setup_server():
-    
-    class Root:
-        def index(self):
-            return cherrypy.request.wsgi_environ['SERVER_PORT']
-        index.exposed = True
-        
-        def upload(self, file):
-            return "Size: %s" % len(file.file.read())
-        upload.exposed = True
-        
-        def tinyupload(self):
-            return cherrypy.request.body.read()
-        tinyupload.exposed = True
-        tinyupload._cp_config = {'request.body.maxbytes': 100}
-    
-    cherrypy.tree.mount(Root())
-    
-    cherrypy.config.update({
-        'server.socket_host': '0.0.0.0',
-        'server.socket_port': 9876,
-        'server.max_request_body_size': 200,
-        'server.max_request_header_size': 500,
-        'server.socket_timeout': 0.5,
-        
-        # Test explicit server.instance
-        'server.2.instance': 'cherrypy._cpwsgi_server.CPWSGIServer',
-        'server.2.socket_port': 9877,
-        
-        # Test non-numeric <servername>
-        # Also test default server.instance = builtin server
-        'server.yetanother.socket_port': 9878,
-        })
-
-
-#                             Client-side code                             #
-
-from cherrypy.test import helper
-
-class ServerConfigTests(helper.CPWebCase):
-    
-    PORT = 9876
-    
-    def testBasicConfig(self):
-        self.getPage("/")
-        self.assertBody(str(self.PORT))
-    
-    def testAdditionalServers(self):
-        if self.scheme == 'https':
-            return self.skip("not available under ssl")
-        self.PORT = 9877
-        self.getPage("/")
-        self.assertBody(str(self.PORT))
-        self.PORT = 9878
-        self.getPage("/")
-        self.assertBody(str(self.PORT))
-    
-    def testMaxRequestSizePerHandler(self):
-        if getattr(cherrypy.server, "using_apache", False):
-            return self.skip("skipped due to known Apache differences... ")
-        
-        self.getPage('/tinyupload', method="POST",
-                     headers=[('Content-Type', 'text/plain'),
-                              ('Content-Length', '100')],
-                     body="x" * 100)
-        self.assertStatus(200)
-        self.assertBody("x" * 100)
-        
-        self.getPage('/tinyupload', method="POST",
-                     headers=[('Content-Type', 'text/plain'),
-                              ('Content-Length', '101')],
-                     body="x" * 101)
-        self.assertStatus(413)
-    
-    def testMaxRequestSize(self):
-        if getattr(cherrypy.server, "using_apache", False):
-            return self.skip("skipped due to known Apache differences... ")
-        
-        for size in (500, 5000, 50000):
-            self.getPage("/", headers=[('From', "x" * 500)])
-            self.assertStatus(413)
-        
-        # Test for http://www.cherrypy.org/ticket/421
-        # (Incorrect border condition in readline of SizeCheckWrapper).
-        # This hangs in rev 891 and earlier.
-        lines256 = "x" * 248
-        self.getPage("/",
-                     headers=[('Host', '%s:%s' % (self.HOST, self.PORT)),
-                              ('From', lines256)])
-        
-        # Test upload
-        body = '\r\n'.join([
-            '--x',
-            'Content-Disposition: form-data; name="file"; filename="hello.txt"',
-            'Content-Type: text/plain',
-            '',
-            '%s',
-            '--x--'])
-        partlen = 200 - len(body)
-        b = body % ("x" * partlen)
-        h = [("Content-type", "multipart/form-data; boundary=x"),
-             ("Content-Length", "%s" % len(b))]
-        self.getPage('/upload', h, "POST", b)
-        self.assertBody('Size: %d' % partlen)
-        
-        b = body % ("x" * 200)
-        h = [("Content-type", "multipart/form-data; boundary=x"),
-             ("Content-Length", "%s" % len(b))]
-        self.getPage('/upload', h, "POST", b)
-        self.assertStatus(413)
-
-
-
-if __name__ == '__main__':
-    helper.testmain()
--- a/bundled/cherrypy/cherrypy/test/test_conn.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,687 +0,0 @@
-"""Tests for TCP connection handling, including proper and timely close."""
-
-from cherrypy.test import test
-test.prefer_parent_path()
-
-from httplib import HTTPConnection, HTTPSConnection, NotConnected, BadStatusLine
-import urllib
-import socket
-import sys
-import time
-timeout = 1
-
-
-import cherrypy
-from cherrypy.test import webtest
-from cherrypy import _cperror
-
-
-pov = 'pPeErRsSiIsStTeEnNcCeE oOfF vViIsSiIoOnN'
-
-def setup_server():
-    
-    def raise500():
-        raise cherrypy.HTTPError(500)
-    
-    class Root:
-        
-        def index(self):
-            return pov
-        index.exposed = True
-        page1 = index
-        page2 = index
-        page3 = index
-        
-        def hello(self):
-            return "Hello, world!"
-        hello.exposed = True
-        
-        def timeout(self, t):
-            return str(cherrypy.server.httpserver.timeout)
-        timeout.exposed = True
-        
-        def stream(self, set_cl=False):
-            if set_cl:
-                cherrypy.response.headers['Content-Length'] = 10
-            
-            def content():
-                for x in range(10):
-                    yield str(x)
-            
-            return content()
-        stream.exposed = True
-        stream._cp_config = {'response.stream': True}
-        
-        def error(self, code=500):
-            raise cherrypy.HTTPError(code)
-        error.exposed = True
-        
-        def upload(self):
-            if not cherrypy.request.method == 'POST':
-                raise AssertionError("'POST' != request.method %r" %
-                                     cherrypy.request.method)
-            return "thanks for '%s'" % cherrypy.request.body.read()
-        upload.exposed = True
-        
-        def custom(self, response_code):
-            cherrypy.response.status = response_code
-            return "Code = %s" % response_code
-        custom.exposed = True
-        
-        def err_before_read(self):
-            return "ok"
-        err_before_read.exposed = True
-        err_before_read._cp_config = {'hooks.on_start_resource': raise500}
-
-        def one_megabyte_of_a(self):
-            return ["a" * 1024] * 1024
-        one_megabyte_of_a.exposed = True
-    
-    cherrypy.tree.mount(Root())
-    cherrypy.config.update({
-        'server.max_request_body_size': 1001,
-        'server.socket_timeout': timeout,
-        })
-
-
-from cherrypy.test import helper
-
-class ConnectionCloseTests(helper.CPWebCase):
-    
-    def test_HTTP11(self):
-        if cherrypy.server.protocol_version != "HTTP/1.1":
-            return self.skip()
-        
-        self.PROTOCOL = "HTTP/1.1"
-        
-        self.persistent = True
-        
-        # Make the first request and assert there's no "Connection: close".
-        self.getPage("/")
-        self.assertStatus('200 OK')
-        self.assertBody(pov)
-        self.assertNoHeader("Connection")
-        
-        # Make another request on the same connection.
-        self.getPage("/page1")
-        self.assertStatus('200 OK')
-        self.assertBody(pov)
-        self.assertNoHeader("Connection")
-        
-        # Test client-side close.
-        self.getPage("/page2", headers=[("Connection", "close")])
-        self.assertStatus('200 OK')
-        self.assertBody(pov)
-        self.assertHeader("Connection", "close")
-        
-        # Make another request on the same connection, which should error.
-        self.assertRaises(NotConnected, self.getPage, "/")
-    
-    def test_Streaming_no_len(self):
-        self._streaming(set_cl=False)
-    
-    def test_Streaming_with_len(self):
-        self._streaming(set_cl=True)
-    
-    def _streaming(self, set_cl):
-        if cherrypy.server.protocol_version == "HTTP/1.1":
-            self.PROTOCOL = "HTTP/1.1"
-            
-            self.persistent = True
-            
-            # Make the first request and assert there's no "Connection: close".
-            self.getPage("/")
-            self.assertStatus('200 OK')
-            self.assertBody(pov)
-            self.assertNoHeader("Connection")
-            
-            # Make another, streamed request on the same connection.
-            if set_cl:
-                # When a Content-Length is provided, the content should stream
-                # without closing the connection.
-                self.getPage("/stream?set_cl=Yes")
-                self.assertHeader("Content-Length")
-                self.assertNoHeader("Connection", "close")
-                self.assertNoHeader("Transfer-Encoding")
-                
-                self.assertStatus('200 OK')
-                self.assertBody('0123456789')
-            else:
-                # When no Content-Length response header is provided,
-                # streamed output will either close the connection, or use
-                # chunked encoding, to determine transfer-length.
-                self.getPage("/stream")
-                self.assertNoHeader("Content-Length")
-                self.assertStatus('200 OK')
-                self.assertBody('0123456789')
-                
-                chunked_response = False
-                for k, v in self.headers:
-                    if k.lower() == "transfer-encoding":
-                        if str(v) == "chunked":
-                            chunked_response = True
-                
-                if chunked_response:
-                    self.assertNoHeader("Connection", "close")
-                else:
-                    self.assertHeader("Connection", "close")
-                    
-                    # Make another request on the same connection, which should error.
-                    self.assertRaises(NotConnected, self.getPage, "/")
-                
-                # Try HEAD. See http://www.cherrypy.org/ticket/864.
-                self.getPage("/stream", method='HEAD')
-                self.assertStatus('200 OK')
-                self.assertBody('')
-                self.assertNoHeader("Transfer-Encoding")
-        else:
-            self.PROTOCOL = "HTTP/1.0"
-            
-            self.persistent = True
-            
-            # Make the first request and assert Keep-Alive.
-            self.getPage("/", headers=[("Connection", "Keep-Alive")])
-            self.assertStatus('200 OK')
-            self.assertBody(pov)
-            self.assertHeader("Connection", "Keep-Alive")
-            
-            # Make another, streamed request on the same connection.
-            if set_cl:
-                # When a Content-Length is provided, the content should
-                # stream without closing the connection.
-                self.getPage("/stream?set_cl=Yes",
-                             headers=[("Connection", "Keep-Alive")])
-                self.assertHeader("Content-Length")
-                self.assertHeader("Connection", "Keep-Alive")
-                self.assertNoHeader("Transfer-Encoding")
-                self.assertStatus('200 OK')
-                self.assertBody('0123456789')
-            else:
-                # When a Content-Length is not provided,
-                # the server should close the connection.
-                self.getPage("/stream", headers=[("Connection", "Keep-Alive")])
-                self.assertStatus('200 OK')
-                self.assertBody('0123456789')
-                
-                self.assertNoHeader("Content-Length")
-                self.assertNoHeader("Connection", "Keep-Alive")
-                self.assertNoHeader("Transfer-Encoding")
-                
-                # Make another request on the same connection, which should error.
-                self.assertRaises(NotConnected, self.getPage, "/")
-    
-    def test_HTTP10_KeepAlive(self):
-        self.PROTOCOL = "HTTP/1.0"
-        if self.scheme == "https":
-            self.HTTP_CONN = HTTPSConnection
-        else:
-            self.HTTP_CONN = HTTPConnection
-        
-        # Test a normal HTTP/1.0 request.
-        self.getPage("/page2")
-        self.assertStatus('200 OK')
-        self.assertBody(pov)
-        # Apache, for example, may emit a Connection header even for HTTP/1.0
-##        self.assertNoHeader("Connection")
-        
-        # Test a keep-alive HTTP/1.0 request.
-        self.persistent = True
-        
-        self.getPage("/page3", headers=[("Connection", "Keep-Alive")])
-        self.assertStatus('200 OK')
-        self.assertBody(pov)
-        self.assertHeader("Connection", "Keep-Alive")
-        
-        # Remove the keep-alive header again.
-        self.getPage("/page3")
-        self.assertStatus('200 OK')
-        self.assertBody(pov)
-        # Apache, for example, may emit a Connection header even for HTTP/1.0
-##        self.assertNoHeader("Connection")
-
-
-class PipelineTests(helper.CPWebCase):
-    
-    def test_HTTP11_Timeout(self):
-        # If we timeout without sending any data,
-        # the server will close the conn with a 408.
-        if cherrypy.server.protocol_version != "HTTP/1.1":
-            return self.skip()
-        
-        self.PROTOCOL = "HTTP/1.1"
-        
-        # Connect but send nothing.
-        self.persistent = True
-        conn = self.HTTP_CONN
-        conn.auto_open = False
-        conn.connect()
-        
-        # Wait for our socket timeout
-        time.sleep(timeout * 2)
-        
-        # The request should have returned 408 already.
-        response = conn.response_class(conn.sock, method="GET")
-        response.begin()
-        self.assertEqual(response.status, 408)
-        conn.close()
-        
-        # Connect but send half the headers only.
-        self.persistent = True
-        conn = self.HTTP_CONN
-        conn.auto_open = False
-        conn.connect()
-        conn.send('GET /hello HTTP/1.1')
-        conn.send(("Host: %s" % self.HOST).encode('ascii'))
-        
-        # Wait for our socket timeout
-        time.sleep(timeout * 2)
-        
-        # The conn should have already sent 408.
-        response = conn.response_class(conn.sock, method="GET")
-        response.begin()
-        self.assertEqual(response.status, 408)
-        conn.close()
-    
-    def test_HTTP11_Timeout_after_request(self):
-        # If we timeout after at least one request has succeeded,
-        # the server will close the conn without 408.
-        if cherrypy.server.protocol_version != "HTTP/1.1":
-            return self.skip()
-        
-        self.PROTOCOL = "HTTP/1.1"
-        
-        # Make an initial request
-        self.persistent = True
-        conn = self.HTTP_CONN
-        conn.putrequest("GET", "/timeout?t=%s" % timeout, skip_host=True)
-        conn.putheader("Host", self.HOST)
-        conn.endheaders()
-        response = conn.response_class(conn.sock, method="GET")
-        response.begin()
-        self.assertEqual(response.status, 200)
-        self.body = response.read()
-        self.assertBody(str(timeout))
-        
-        # Make a second request on the same socket
-        conn._output('GET /hello HTTP/1.1')
-        conn._output("Host: %s" % self.HOST)
-        conn._send_output()
-        response = conn.response_class(conn.sock, method="GET")
-        response.begin()
-        self.assertEqual(response.status, 200)
-        self.body = response.read()
-        self.assertBody("Hello, world!")
-        
-        # Wait for our socket timeout
-        time.sleep(timeout * 2)
-        
-        # Make another request on the same socket, which should error
-        conn._output('GET /hello HTTP/1.1')
-        conn._output("Host: %s" % self.HOST)
-        conn._send_output()
-        response = conn.response_class(conn.sock, method="GET")
-        try:
-            response.begin()
-        except:
-            if not isinstance(sys.exc_info()[1],
-                              (socket.error, BadStatusLine)):
-                self.fail("Writing to timed out socket didn't fail"
-                          " as it should have: %s" % sys.exc_info()[1])
-        else:
-            if response.status != 408:
-                self.fail("Writing to timed out socket didn't fail"
-                          " as it should have: %s" %
-                          response.read())
-        
-        conn.close()
-        
-        # Make another request on a new socket, which should work
-        self.persistent = True
-        conn = self.HTTP_CONN
-        conn.putrequest("GET", "/", skip_host=True)
-        conn.putheader("Host", self.HOST)
-        conn.endheaders()
-        response = conn.response_class(conn.sock, method="GET")
-        response.begin()
-        self.assertEqual(response.status, 200)
-        self.body = response.read()
-        self.assertBody(pov)
-
-        
-        # Make another request on the same socket,
-        # but timeout on the headers
-        conn.send('GET /hello HTTP/1.1')
-        # Wait for our socket timeout
-        time.sleep(timeout * 2)
-        response = conn.response_class(conn.sock, method="GET")
-        try:
-            response.begin()
-        except:
-            if not isinstance(sys.exc_info()[1],
-                              (socket.error, BadStatusLine)):
-                self.fail("Writing to timed out socket didn't fail"
-                          " as it should have: %s" % sys.exc_info()[1])
-        else:
-            self.fail("Writing to timed out socket didn't fail"
-                      " as it should have: %s" %
-                      response.read())
-        
-        conn.close()
-        
-        # Retry the request on a new connection, which should work
-        self.persistent = True
-        conn = self.HTTP_CONN
-        conn.putrequest("GET", "/", skip_host=True)
-        conn.putheader("Host", self.HOST)
-        conn.endheaders()
-        response = conn.response_class(conn.sock, method="GET")
-        response.begin()
-        self.assertEqual(response.status, 200)
-        self.body = response.read()
-        self.assertBody(pov)
-        conn.close()
-    
-    def test_HTTP11_pipelining(self):
-        if cherrypy.server.protocol_version != "HTTP/1.1":
-            return self.skip()
-        
-        self.PROTOCOL = "HTTP/1.1"
-        
-        # Test pipelining. httplib doesn't support this directly.
-        self.persistent = True
-        conn = self.HTTP_CONN
-        
-        # Put request 1
-        conn.putrequest("GET", "/hello", skip_host=True)
-        conn.putheader("Host", self.HOST)
-        conn.endheaders()
-        
-        for trial in range(5):
-            # Put next request
-            conn._output('GET /hello HTTP/1.1')
-            conn._output("Host: %s" % self.HOST)
-            conn._send_output()
-            
-            # Retrieve previous response
-            response = conn.response_class(conn.sock, method="GET")
-            response.begin()
-            body = response.read()
-            self.assertEqual(response.status, 200)
-            self.assertEqual(body, "Hello, world!")
-        
-        # Retrieve final response
-        response = conn.response_class(conn.sock, method="GET")
-        response.begin()
-        body = response.read()
-        self.assertEqual(response.status, 200)
-        self.assertEqual(body, "Hello, world!")
-        
-        conn.close()
-    
-    def test_100_Continue(self):
-        if cherrypy.server.protocol_version != "HTTP/1.1":
-            return self.skip()
-        
-        self.PROTOCOL = "HTTP/1.1"
-        
-        self.persistent = True
-        conn = self.HTTP_CONN
-        
-        # Try a page without an Expect request header first.
-        # Note that httplib's response.begin automatically ignores
-        # 100 Continue responses, so we must manually check for it.
-        conn.putrequest("POST", "/upload", skip_host=True)
-        conn.putheader("Host", self.HOST)
-        conn.putheader("Content-Type", "text/plain")
-        conn.putheader("Content-Length", "4")
-        conn.endheaders()
-        conn.send("d'oh")
-        response = conn.response_class(conn.sock, method="POST")
-        version, status, reason = response._read_status()
-        self.assertNotEqual(status, 100)
-        conn.close()
-        
-        # Now try a page with an Expect header...
-        conn.connect()
-        conn.putrequest("POST", "/upload", skip_host=True)
-        conn.putheader("Host", self.HOST)
-        conn.putheader("Content-Type", "text/plain")
-        conn.putheader("Content-Length", "17")
-        conn.putheader("Expect", "100-continue")
-        conn.endheaders()
-        response = conn.response_class(conn.sock, method="POST")
-        
-        # ...assert and then skip the 100 response
-        version, status, reason = response._read_status()
-        self.assertEqual(status, 100)
-        while True:
-            line = response.fp.readline().strip()
-            if line:
-                self.fail("100 Continue should not output any headers. Got %r" % line)
-            else:
-                break
-        
-        # ...send the body
-        conn.send("I am a small file")
-        
-        # ...get the final response
-        response.begin()
-        self.status, self.headers, self.body = webtest.shb(response)
-        self.assertStatus(200)
-        self.assertBody("thanks for 'I am a small file'")
-        conn.close()
-
-
-class ConnectionTests(helper.CPWebCase):
-    
-    def test_readall_or_close(self):
-        if cherrypy.server.protocol_version != "HTTP/1.1":
-            return self.skip()
-        
-        self.PROTOCOL = "HTTP/1.1"
-        
-        if self.scheme == "https":
-            self.HTTP_CONN = HTTPSConnection
-        else:
-            self.HTTP_CONN = HTTPConnection
-        
-        # Test a max of 0 (the default) and then reset to what it was above.
-        old_max = cherrypy.server.max_request_body_size
-        for new_max in (0, old_max):
-            cherrypy.server.max_request_body_size = new_max
-            
-            self.persistent = True
-            conn = self.HTTP_CONN
-            
-            # Get a POST page with an error
-            conn.putrequest("POST", "/err_before_read", skip_host=True)
-            conn.putheader("Host", self.HOST)
-            conn.putheader("Content-Type", "text/plain")
-            conn.putheader("Content-Length", "1000")
-            conn.putheader("Expect", "100-continue")
-            conn.endheaders()
-            response = conn.response_class(conn.sock, method="POST")
-            
-            # ...assert and then skip the 100 response
-            version, status, reason = response._read_status()
-            self.assertEqual(status, 100)
-            while True:
-                skip = response.fp.readline().strip()
-                if not skip:
-                    break
-            
-            # ...send the body
-            conn.send("x" * 1000)
-            
-            # ...get the final response
-            response.begin()
-            self.status, self.headers, self.body = webtest.shb(response)
-            self.assertStatus(500)
-            
-            # Now try a working page with an Expect header...
-            conn._output('POST /upload HTTP/1.1')
-            conn._output("Host: %s" % self.HOST)
-            conn._output("Content-Type: text/plain")
-            conn._output("Content-Length: 17")
-            conn._output("Expect: 100-continue")
-            conn._send_output()
-            response = conn.response_class(conn.sock, method="POST")
-            
-            # ...assert and then skip the 100 response
-            version, status, reason = response._read_status()
-            self.assertEqual(status, 100)
-            while True:
-                skip = response.fp.readline().strip()
-                if not skip:
-                    break
-            
-            # ...send the body
-            conn.send("I am a small file")
-            
-            # ...get the final response
-            response.begin()
-            self.status, self.headers, self.body = webtest.shb(response)
-            self.assertStatus(200)
-            self.assertBody("thanks for 'I am a small file'")
-            conn.close()
-    
-    def test_No_Message_Body(self):
-        if cherrypy.server.protocol_version != "HTTP/1.1":
-            return self.skip()
-        
-        self.PROTOCOL = "HTTP/1.1"
-        
-        # Set our HTTP_CONN to an instance so it persists between requests.
-        self.persistent = True
-        
-        # Make the first request and assert there's no "Connection: close".
-        self.getPage("/")
-        self.assertStatus('200 OK')
-        self.assertBody(pov)
-        self.assertNoHeader("Connection")
-        
-        # Make a 204 request on the same connection.
-        self.getPage("/custom/204")
-        self.assertStatus(204)
-        self.assertNoHeader("Content-Length")
-        self.assertBody("")
-        self.assertNoHeader("Connection")
-        
-        # Make a 304 request on the same connection.
-        self.getPage("/custom/304")
-        self.assertStatus(304)
-        self.assertNoHeader("Content-Length")
-        self.assertBody("")
-        self.assertNoHeader("Connection")
-    
-    def test_Chunked_Encoding(self):
-        if cherrypy.server.protocol_version != "HTTP/1.1":
-            return self.skip()
-        
-        if (hasattr(self, 'harness') and
-            "modpython" in self.harness.__class__.__name__.lower()):
-            # mod_python forbids chunked encoding
-            return self.skip()
-        
-        self.PROTOCOL = "HTTP/1.1"
-        
-        # Set our HTTP_CONN to an instance so it persists between requests.
-        self.persistent = True
-        conn = self.HTTP_CONN
-        
-        # Try a normal chunked request (with extensions)
-        body = ("8;key=value\r\nxx\r\nxxxx\r\n5\r\nyyyyy\r\n0\r\n"
-                "Content-Type: application/json\r\n"
-                "\r\n")
-        conn.putrequest("POST", "/upload", skip_host=True)
-        conn.putheader("Host", self.HOST)
-        conn.putheader("Transfer-Encoding", "chunked")
-        conn.putheader("Trailer", "Content-Type")
-        # Note that this is somewhat malformed:
-        # we shouldn't be sending Content-Length.
-        # RFC 2616 says the server should ignore it.
-        conn.putheader("Content-Length", "3")
-        conn.endheaders()
-        conn.send(body)
-        response = conn.getresponse()
-        self.status, self.headers, self.body = webtest.shb(response)
-        self.assertStatus('200 OK')
-        self.assertBody("thanks for 'xx\r\nxxxxyyyyy'")
-        
-        # Try a chunked request that exceeds server.max_request_body_size.
-        # Note that the delimiters and trailer are included.
-        body = "3e3\r\n" + ("x" * 995) + "\r\n0\r\n\r\n"
-        conn.putrequest("POST", "/upload", skip_host=True)
-        conn.putheader("Host", self.HOST)
-        conn.putheader("Transfer-Encoding", "chunked")
-        conn.putheader("Content-Type", "text/plain")
-        # Chunked requests don't need a content-length
-##        conn.putheader("Content-Length", len(body))
-        conn.endheaders()
-        conn.send(body)
-        response = conn.getresponse()
-        self.status, self.headers, self.body = webtest.shb(response)
-        self.assertStatus(413)
-        conn.close()
-    
-    def test_Content_Length(self):
-        # Try a non-chunked request where Content-Length exceeds
-        # server.max_request_body_size. Assert error before body send.
-        self.persistent = True
-        conn = self.HTTP_CONN
-        conn.putrequest("POST", "/upload", skip_host=True)
-        conn.putheader("Host", self.HOST)
-        conn.putheader("Content-Type", "text/plain")
-        conn.putheader("Content-Length", "9999")
-        conn.endheaders()
-        response = conn.getresponse()
-        self.status, self.headers, self.body = webtest.shb(response)
-        self.assertStatus(413)
-        self.assertBody("")
-        conn.close()
-    
-    def test_598(self):
-        remote_data_conn = urllib.urlopen('%s://%s:%s/one_megabyte_of_a/' %
-                                          (self.scheme, self.HOST, self.PORT,))
-        buf = remote_data_conn.read(512)
-        time.sleep(timeout * 0.6)
-        remaining = (1024 * 1024) - 512
-        while remaining:
-            data = remote_data_conn.read(remaining)
-            if not data:
-                break
-            else:
-                buf += data
-            remaining -= len(data)
-       
-        self.assertEqual(len(buf), 1024 * 1024)
-        self.assertEqual(buf, "a" * 1024 * 1024)
-        self.assertEqual(remaining, 0)
-        remote_data_conn.close()
-
-
-class BadRequestTests(helper.CPWebCase):
-    
-    def test_No_CRLF(self):
-        self.persistent = True
-        
-        conn = self.HTTP_CONN
-        conn.send('GET /hello HTTP/1.1\n\n')
-        response = conn.response_class(conn.sock, method="GET")
-        response.begin()
-        self.body = response.read()
-        self.assertBody("HTTP requires CRLF terminators")
-        conn.close()
-        
-        conn.connect()
-        conn.send('GET /hello HTTP/1.1\r\n\n')
-        response = conn.response_class(conn.sock, method="GET")
-        response.begin()
-        self.body = response.read()
-        self.assertBody("HTTP requires CRLF terminators")
-        conn.close()
-
-
-
-if __name__ == "__main__":
-    helper.testmain()
--- a/bundled/cherrypy/cherrypy/test/test_core.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,611 +0,0 @@
-"""Basic tests for the CherryPy core: request handling."""
-
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import os
-localDir = os.path.dirname(__file__)
-import sys
-import types
-from httplib import IncompleteRead
-
-import cherrypy
-from cherrypy import _cptools, tools
-from cherrypy.lib import httputil, static
-
-
-favicon_path = os.path.join(os.getcwd(), localDir, "../favicon.ico")
-
-def setup_server():
-    class Root:
-        
-        def index(self):
-            return "hello"
-        index.exposed = True
-        
-        favicon_ico = tools.staticfile.handler(filename=favicon_path)
-        
-        def defct(self, newct):
-            newct = "text/%s" % newct
-            cherrypy.config.update({'tools.response_headers.on': True,
-                                    'tools.response_headers.headers':
-                                    [('Content-Type', newct)]})
-        defct.exposed = True
-        
-        def baseurl(self, path_info, relative=None):
-            return cherrypy.url(path_info, relative=bool(relative))
-        baseurl.exposed = True
-    
-    root = Root()
-    
-    
-    class TestType(type):
-        """Metaclass which automatically exposes all functions in each subclass,
-        and adds an instance of the subclass as an attribute of root.
-        """
-        def __init__(cls, name, bases, dct):
-            type.__init__(cls, name, bases, dct)
-            for value in dct.itervalues():
-                if isinstance(value, types.FunctionType):
-                    value.exposed = True
-            setattr(root, name.lower(), cls())
-    class Test(object):
-        __metaclass__ = TestType
-    
-    
-    class URL(Test):
-        
-        _cp_config = {'tools.trailing_slash.on': False}
-        
-        def index(self, path_info, relative=None):
-            if relative != 'server':
-                relative = bool(relative)
-            return cherrypy.url(path_info, relative=relative)
-        
-        def leaf(self, path_info, relative=None):
-            if relative != 'server':
-                relative = bool(relative)
-            return cherrypy.url(path_info, relative=relative)
-
-
-    class Status(Test):
-        
-        def index(self):
-            return "normal"
-        
-        def blank(self):
-            cherrypy.response.status = ""
-        
-        # According to RFC 2616, new status codes are OK as long as they
-        # are between 100 and 599.
-        
-        # Here is an illegal code...
-        def illegal(self):
-            cherrypy.response.status = 781
-            return "oops"
-        
-        # ...and here is an unknown but legal code.
-        def unknown(self):
-            cherrypy.response.status = "431 My custom error"
-            return "funky"
-        
-        # Non-numeric code
-        def bad(self):
-            cherrypy.response.status = "error"
-            return "bad news"
-
-
-    class Redirect(Test):
-        
-        class Error:
-            _cp_config = {"tools.err_redirect.on": True,
-                          "tools.err_redirect.url": "/errpage",
-                          "tools.err_redirect.internal": False,
-                          }
-            
-            def index(self):
-                raise NameError("redirect_test")
-            index.exposed = True
-        error = Error()
-        
-        def index(self):
-            return "child"
-        
-        def by_code(self, code):
-            raise cherrypy.HTTPRedirect("somewhere else", code)
-        by_code._cp_config = {'tools.trailing_slash.extra': True}
-        
-        def nomodify(self):
-            raise cherrypy.HTTPRedirect("", 304)
-        
-        def proxy(self):
-            raise cherrypy.HTTPRedirect("proxy", 305)
-        
-        def stringify(self):
-            return str(cherrypy.HTTPRedirect("/"))
-        
-        def fragment(self, frag):
-            raise cherrypy.HTTPRedirect("/some/url#%s" % frag)
-    
-    def login_redir():
-        if not getattr(cherrypy.request, "login", None):
-            raise cherrypy.InternalRedirect("/internalredirect/login")
-    tools.login_redir = _cptools.Tool('before_handler', login_redir)
-    
-    def redir_custom():
-        raise cherrypy.InternalRedirect("/internalredirect/custom_err")
-    
-    class InternalRedirect(Test):
-        
-        def index(self):
-            raise cherrypy.InternalRedirect("/")
-        
-        def choke(self):
-            return 3 / 0
-        choke.exposed = True
-        choke._cp_config = {'hooks.before_error_response': redir_custom}
-        
-        def relative(self, a, b):
-            raise cherrypy.InternalRedirect("cousin?t=6")
-        
-        def cousin(self, t):
-            assert cherrypy.request.prev.closed
-            return cherrypy.request.prev.query_string
-        
-        def petshop(self, user_id):
-            if user_id == "parrot":
-                # Trade it for a slug when redirecting
-                raise cherrypy.InternalRedirect('/image/getImagesByUser?user_id=slug')
-            elif user_id == "terrier":
-                # Trade it for a fish when redirecting
-                raise cherrypy.InternalRedirect('/image/getImagesByUser?user_id=fish')
-            else:
-                # This should pass the user_id through to getImagesByUser
-                raise cherrypy.InternalRedirect(
-                    '/image/getImagesByUser?user_id=%s' % str(user_id))
-        
-        # We support Python 2.3, but the @-deco syntax would look like this:
-        # @tools.login_redir()
-        def secure(self):
-            return "Welcome!"
-        secure = tools.login_redir()(secure)
-        # Since calling the tool returns the same function you pass in,
-        # you could skip binding the return value, and just write:
-        # tools.login_redir()(secure)
-        
-        def login(self):
-            return "Please log in"
-        
-        def custom_err(self):
-            return "Something went horribly wrong."
-        
-        def early_ir(self, arg):
-            return "whatever"
-        early_ir._cp_config = {'hooks.before_request_body': redir_custom}
-    
-    
-    class Image(Test):
-        
-        def getImagesByUser(self, user_id):
-            return "0 images for %s" % user_id
-
-
-    class Flatten(Test):
-        
-        def as_string(self):
-            return "content"
-        
-        def as_list(self):
-            return ["con", "tent"]
-        
-        def as_yield(self):
-            yield "content"
-        
-        def as_dblyield(self):
-            yield self.as_yield()
-        as_dblyield._cp_config = {'tools.flatten.on': True}
-        
-        def as_refyield(self):
-            for chunk in self.as_yield():
-                yield chunk
-    
-    
-    class Ranges(Test):
-        
-        def get_ranges(self, bytes):
-            return repr(httputil.get_ranges('bytes=%s' % bytes, 8))
-        
-        def slice_file(self):
-            path = os.path.join(os.getcwd(), os.path.dirname(__file__))
-            return static.serve_file(os.path.join(path, "static/index.html"))
-
-
-    class Cookies(Test):
-        
-        def single(self, name):
-            cookie = cherrypy.request.cookie[name]
-            # Python2's SimpleCookie.__setitem__ won't take unicode keys.
-            cherrypy.response.cookie[str(name)] = cookie.value
-        
-        def multiple(self, names):
-            for name in names:
-                cookie = cherrypy.request.cookie[name]
-                # Python2's SimpleCookie.__setitem__ won't take unicode keys.
-                cherrypy.response.cookie[str(name)] = cookie.value
-
-
-    if sys.version_info >= (2, 5):
-        from cherrypy.test import py25
-        Root.expose_dec = py25.ExposeExamples()
-    
-    cherrypy.tree.mount(root)
-
-
-#                             Client-side code                             #
-
-from cherrypy.test import helper
-
-class CoreRequestHandlingTest(helper.CPWebCase):
-
-    def testStatus(self):
-        self.getPage("/status/")
-        self.assertBody('normal')
-        self.assertStatus(200)
-        
-        self.getPage("/status/blank")
-        self.assertBody('')
-        self.assertStatus(200)
-        
-        self.getPage("/status/illegal")
-        self.assertStatus(500)
-        msg = "Illegal response status from server (781 is out of range)."
-        self.assertErrorPage(500, msg)
-        
-        if not getattr(cherrypy.server, 'using_apache', False):
-            self.getPage("/status/unknown")
-            self.assertBody('funky')
-            self.assertStatus(431)
-        
-        self.getPage("/status/bad")
-        self.assertStatus(500)
-        msg = "Illegal response status from server ('error' is non-numeric)."
-        self.assertErrorPage(500, msg)
-    
-    def testSlashes(self):
-        # Test that requests for index methods without a trailing slash
-        # get redirected to the same URI path with a trailing slash.
-        # Make sure GET params are preserved.
-        self.getPage("/redirect?id=3")
-        self.assertStatus(301)
-        self.assertInBody("<a href='%s/redirect/?id=3'>"
-                          "%s/redirect/?id=3</a>" % (self.base(), self.base()))
-        
-        if self.prefix():
-            # Corner case: the "trailing slash" redirect could be tricky if
-            # we're using a virtual root and the URI is "/vroot" (no slash).
-            self.getPage("")
-            self.assertStatus(301)
-            self.assertInBody("<a href='%s/'>%s/</a>" %
-                              (self.base(), self.base()))
-        
-        # Test that requests for NON-index methods WITH a trailing slash
-        # get redirected to the same URI path WITHOUT a trailing slash.
-        # Make sure GET params are preserved.
-        self.getPage("/redirect/by_code/?code=307")
-        self.assertStatus(301)
-        self.assertInBody("<a href='%s/redirect/by_code?code=307'>"
-                          "%s/redirect/by_code?code=307</a>"
-                          % (self.base(), self.base()))
-        
-        # If the trailing_slash tool is off, CP should just continue
-        # as if the slashes were correct. But it needs some help
-        # inside cherrypy.url to form correct output.
-        self.getPage('/url?path_info=page1')
-        self.assertBody('%s/url/page1' % self.base())
-        self.getPage('/url/leaf/?path_info=page1')
-        self.assertBody('%s/url/page1' % self.base())
-    
-    def testRedirect(self):
-        self.getPage("/redirect/")
-        self.assertBody('child')
-        self.assertStatus(200)
-        
-        self.getPage("/redirect/by_code?code=300")
-        self.assertMatchesBody(r"<a href='(.*)somewhere else'>\1somewhere else</a>")
-        self.assertStatus(300)
-        
-        self.getPage("/redirect/by_code?code=301")
-        self.assertMatchesBody(r"<a href='(.*)somewhere else'>\1somewhere else</a>")
-        self.assertStatus(301)
-        
-        self.getPage("/redirect/by_code?code=302")
-        self.assertMatchesBody(r"<a href='(.*)somewhere else'>\1somewhere else</a>")
-        self.assertStatus(302)
-        
-        self.getPage("/redirect/by_code?code=303")
-        self.assertMatchesBody(r"<a href='(.*)somewhere else'>\1somewhere else</a>")
-        self.assertStatus(303)
-        
-        self.getPage("/redirect/by_code?code=307")
-        self.assertMatchesBody(r"<a href='(.*)somewhere else'>\1somewhere else</a>")
-        self.assertStatus(307)
-        
-        self.getPage("/redirect/nomodify")
-        self.assertBody('')
-        self.assertStatus(304)
-        
-        self.getPage("/redirect/proxy")
-        self.assertBody('')
-        self.assertStatus(305)
-        
-        # HTTPRedirect on error
-        self.getPage("/redirect/error/")
-        self.assertStatus(('302 Found', '303 See Other'))
-        self.assertInBody('/errpage')
-        
-        # Make sure str(HTTPRedirect()) works.
-        self.getPage("/redirect/stringify", protocol="HTTP/1.0")
-        self.assertStatus(200)
-        self.assertBody("(['%s/'], 302)" % self.base())
-        if cherrypy.server.protocol_version == "HTTP/1.1":
-            self.getPage("/redirect/stringify", protocol="HTTP/1.1")
-            self.assertStatus(200)
-            self.assertBody("(['%s/'], 303)" % self.base())
-        
-        # check that #fragments are handled properly
-        # http://skrb.org/ietf/http_errata.html#location-fragments
-        frag = "foo"
-        self.getPage("/redirect/fragment/%s" % frag)
-        self.assertMatchesBody(r"<a href='(.*)\/some\/url\#%s'>\1\/some\/url\#%s</a>" % (frag, frag))
-        loc = self.assertHeader('Location')
-        assert loc.endswith("#%s" % frag)
-        self.assertStatus(('302 Found', '303 See Other'))
-    
-    def test_InternalRedirect(self):
-        # InternalRedirect
-        self.getPage("/internalredirect/")
-        self.assertBody('hello')
-        self.assertStatus(200)
-        
-        # Test passthrough
-        self.getPage("/internalredirect/petshop?user_id=Sir-not-appearing-in-this-film")
-        self.assertBody('0 images for Sir-not-appearing-in-this-film')
-        self.assertStatus(200)
-        
-        # Test args
-        self.getPage("/internalredirect/petshop?user_id=parrot")
-        self.assertBody('0 images for slug')
-        self.assertStatus(200)
-        
-        # Test POST
-        self.getPage("/internalredirect/petshop", method="POST",
-                     body="user_id=terrier")
-        self.assertBody('0 images for fish')
-        self.assertStatus(200)
-        
-        # Test ir before body read
-        self.getPage("/internalredirect/early_ir", method="POST",
-                     body="arg=aha!")
-        self.assertBody("Something went horribly wrong.")
-        self.assertStatus(200)
-        
-        self.getPage("/internalredirect/secure")
-        self.assertBody('Please log in')
-        self.assertStatus(200)
-        
-        # Relative path in InternalRedirect.
-        # Also tests request.prev.
-        self.getPage("/internalredirect/relative?a=3&b=5")
-        self.assertBody("a=3&b=5")
-        self.assertStatus(200)
-        
-        # InternalRedirect on error
-        self.getPage("/internalredirect/choke")
-        self.assertStatus(200)
-        self.assertBody("Something went horribly wrong.")
-    
-    def testFlatten(self):
-        for url in ["/flatten/as_string", "/flatten/as_list",
-                    "/flatten/as_yield", "/flatten/as_dblyield",
-                    "/flatten/as_refyield"]:
-            self.getPage(url)
-            self.assertBody('content')
-    
-    def testRanges(self):
-        self.getPage("/ranges/get_ranges?bytes=3-6")
-        self.assertBody("[(3, 7)]")
-        
-        # Test multiple ranges and a suffix-byte-range-spec, for good measure.
-        self.getPage("/ranges/get_ranges?bytes=2-4,-1")
-        self.assertBody("[(2, 5), (7, 8)]")
-        
-        # Get a partial file.
-        if cherrypy.server.protocol_version == "HTTP/1.1":
-            self.getPage("/ranges/slice_file", [('Range', 'bytes=2-5')])
-            self.assertStatus(206)
-            self.assertHeader("Content-Type", "text/html;charset=utf-8")
-            self.assertHeader("Content-Range", "bytes 2-5/14")
-            self.assertBody("llo,")
-            
-            # What happens with overlapping ranges (and out of order, too)?
-            self.getPage("/ranges/slice_file", [('Range', 'bytes=4-6,2-5')])
-            self.assertStatus(206)
-            ct = self.assertHeader("Content-Type")
-            expected_type = "multipart/byteranges; boundary="
-            self.assert_(ct.startswith(expected_type))
-            boundary = ct[len(expected_type):]
-            expected_body = ("\r\n--%s\r\n"
-                             "Content-type: text/html\r\n"
-                             "Content-range: bytes 4-6/14\r\n"
-                             "\r\n"
-                             "o, \r\n"
-                             "--%s\r\n"
-                             "Content-type: text/html\r\n"
-                             "Content-range: bytes 2-5/14\r\n"
-                             "\r\n"
-                             "llo,\r\n"
-                             "--%s--\r\n" % (boundary, boundary, boundary))
-            self.assertBody(expected_body)
-            self.assertHeader("Content-Length")
-            
-            # Test "416 Requested Range Not Satisfiable"
-            self.getPage("/ranges/slice_file", [('Range', 'bytes=2300-2900')])
-            self.assertStatus(416)
-            # "When this status code is returned for a byte-range request,
-            # the response SHOULD include a Content-Range entity-header
-            # field specifying the current length of the selected resource"
-            self.assertHeader("Content-Range", "bytes */14")
-        elif cherrypy.server.protocol_version == "HTTP/1.0":
-            # Test Range behavior with HTTP/1.0 request
-            self.getPage("/ranges/slice_file", [('Range', 'bytes=2-5')])
-            self.assertStatus(200)
-            self.assertBody("Hello, world\r\n")
-    
-    def testFavicon(self):
-        # favicon.ico is served by staticfile.
-        icofilename = os.path.join(localDir, "../favicon.ico")
-        icofile = open(icofilename, "rb")
-        data = icofile.read()
-        icofile.close()
-        
-        self.getPage("/favicon.ico")
-        self.assertBody(data)
-    
-    def testCookies(self):
-        if sys.version_info >= (2, 5):
-            header_value = lambda x: x
-        else:
-            header_value = lambda x: x+';'
-        
-        self.getPage("/cookies/single?name=First",
-                     [('Cookie', 'First=Dinsdale;')])
-        self.assertHeader('Set-Cookie', header_value('First=Dinsdale'))
-        
-        self.getPage("/cookies/multiple?names=First&names=Last",
-                     [('Cookie', 'First=Dinsdale; Last=Piranha;'),
-                      ])
-        self.assertHeader('Set-Cookie', header_value('First=Dinsdale'))
-        self.assertHeader('Set-Cookie', header_value('Last=Piranha'))
-        
-        self.getPage("/cookies/single?name=Something-With:Colon",
-            [('Cookie', 'Something-With:Colon=some-value')])
-        self.assertStatus(400)
-    
-    def testDefaultContentType(self):
-        self.getPage('/')
-        self.assertHeader('Content-Type', 'text/html;charset=utf-8')
-        self.getPage('/defct/plain')
-        self.getPage('/')
-        self.assertHeader('Content-Type', 'text/plain;charset=utf-8')
-        self.getPage('/defct/html')
-    
-    def test_cherrypy_url(self):
-        # Input relative to current
-        self.getPage('/url/leaf?path_info=page1')
-        self.assertBody('%s/url/page1' % self.base())
-        self.getPage('/url/?path_info=page1')
-        self.assertBody('%s/url/page1' % self.base())
-        # Other host header
-        host = 'www.mydomain.example'
-        self.getPage('/url/leaf?path_info=page1',
-                     headers=[('Host', host)])
-        self.assertBody('%s://%s/url/page1' % (self.scheme, host))
-        
-        # Input is 'absolute'; that is, relative to script_name
-        self.getPage('/url/leaf?path_info=/page1')
-        self.assertBody('%s/page1' % self.base())
-        self.getPage('/url/?path_info=/page1')
-        self.assertBody('%s/page1' % self.base())
-        
-        # Single dots
-        self.getPage('/url/leaf?path_info=./page1')
-        self.assertBody('%s/url/page1' % self.base())
-        self.getPage('/url/leaf?path_info=other/./page1')
-        self.assertBody('%s/url/other/page1' % self.base())
-        self.getPage('/url/?path_info=/other/./page1')
-        self.assertBody('%s/other/page1' % self.base())
-        
-        # Double dots
-        self.getPage('/url/leaf?path_info=../page1')
-        self.assertBody('%s/page1' % self.base())
-        self.getPage('/url/leaf?path_info=other/../page1')
-        self.assertBody('%s/url/page1' % self.base())
-        self.getPage('/url/leaf?path_info=/other/../page1')
-        self.assertBody('%s/page1' % self.base())
-        
-        # Output relative to current path or script_name
-        self.getPage('/url/?path_info=page1&relative=True')
-        self.assertBody('page1')
-        self.getPage('/url/leaf?path_info=/page1&relative=True')
-        self.assertBody('../page1')
-        self.getPage('/url/leaf?path_info=page1&relative=True')
-        self.assertBody('page1')
-        self.getPage('/url/leaf?path_info=leaf/page1&relative=True')
-        self.assertBody('leaf/page1')
-        self.getPage('/url/leaf?path_info=../page1&relative=True')
-        self.assertBody('../page1')
-        self.getPage('/url/?path_info=other/../page1&relative=True')
-        self.assertBody('page1')
-        
-        # Output relative to /
-        self.getPage('/baseurl?path_info=ab&relative=True')
-        self.assertBody('ab')
-        # Output relative to /
-        self.getPage('/baseurl?path_info=/ab&relative=True')
-        self.assertBody('ab')
-        
-        # absolute-path references ("server-relative")
-        # Input relative to current
-        self.getPage('/url/leaf?path_info=page1&relative=server')
-        self.assertBody('/url/page1')
-        self.getPage('/url/?path_info=page1&relative=server')
-        self.assertBody('/url/page1')
-        # Input is 'absolute'; that is, relative to script_name
-        self.getPage('/url/leaf?path_info=/page1&relative=server')
-        self.assertBody('/page1')
-        self.getPage('/url/?path_info=/page1&relative=server')
-        self.assertBody('/page1')
-    
-    def test_expose_decorator(self):
-        if not sys.version_info >= (2, 5):
-            return self.skip("skipped (Python 2.5+ only) ")
-        
-        # Test @expose
-        self.getPage("/expose_dec/no_call")
-        self.assertStatus(200)
-        self.assertBody("Mr E. R. Bradshaw")
-        
-        # Test @expose()
-        self.getPage("/expose_dec/call_empty")
-        self.assertStatus(200)
-        self.assertBody("Mrs. B.J. Smegma")
-        
-        # Test @expose("alias")
-        self.getPage("/expose_dec/call_alias")
-        self.assertStatus(200)
-        self.assertBody("Mr Nesbitt")
-        # Does the original name work?
-        self.getPage("/expose_dec/nesbitt")
-        self.assertStatus(200)
-        self.assertBody("Mr Nesbitt")
-        
-        # Test @expose(["alias1", "alias2"])
-        self.getPage("/expose_dec/alias1")
-        self.assertStatus(200)
-        self.assertBody("Mr Ken Andrews")
-        self.getPage("/expose_dec/alias2")
-        self.assertStatus(200)
-        self.assertBody("Mr Ken Andrews")
-        # Does the original name work?
-        self.getPage("/expose_dec/andrews")
-        self.assertStatus(200)
-        self.assertBody("Mr Ken Andrews")
-        
-        # Test @expose(alias="alias")
-        self.getPage("/expose_dec/alias3")
-        self.assertStatus(200)
-        self.assertBody("Mr. and Mrs. Watson")
-
-
-if __name__ == '__main__':
-    helper.testmain()
--- a/bundled/cherrypy/cherrypy/test/test_dynamicobjectmapping.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,302 +0,0 @@
-from cherrypy.test import test
-from cherrypy._cptree import Application
-test.prefer_parent_path()
-
-import cherrypy
-
-script_names = ["", "/foo", "/users/fred/blog", "/corp/blog"]
-
-def setup_server():
-    class SubSubRoot:
-        def index(self):
-            return "SubSubRoot index"
-        index.exposed = True
-
-        def default(self, *args):
-            return "SubSubRoot default"
-        default.exposed = True
-
-        def handler(self):
-            return "SubSubRoot handler"
-        handler.exposed = True
-
-        def dispatch(self):
-            return "SubSubRoot dispatch"
-        dispatch.exposed = True
-
-    subsubnodes = {
-        '1': SubSubRoot(),
-        '2': SubSubRoot(),
-    }
-
-    class SubRoot:
-        def index(self):
-            return "SubRoot index"
-        index.exposed = True
-
-        def default(self, *args):
-            return "SubRoot %s" % (args,)
-        default.exposed = True
-
-        def handler(self):
-            return "SubRoot handler"
-        handler.exposed = True
-
-        def _cp_dispatch(self, vpath):
-            return subsubnodes.get(vpath[0], None)
-
-    subnodes = {
-        '1': SubRoot(),
-        '2': SubRoot(),
-    }
-    class Root:
-        def index(self):
-            return "index"
-        index.exposed = True
-
-        def default(self, *args):
-            return "default %s" % (args,)
-        default.exposed = True
-
-        def handler(self):
-            return "handler"
-        handler.exposed = True
-
-        def _cp_dispatch(self, vpath):
-            return subnodes.get(vpath[0])
-
-    #--------------------------------------------------------------------------
-    # DynamicNodeAndMethodDispatcher example.
-    # This example exposes a fairly naive HTTP api
-    class User(object):
-        def __init__(self, id, name):
-            self.id = id
-            self.name = name
-
-        def __unicode__(self):
-            return unicode(self.name)
-
-    user_lookup = {
-        1: User(1, 'foo'),
-        2: User(2, 'bar'),
-    }
-
-    def make_user(name, id=None):
-        if not id:
-            id = max(*user_lookup.keys()) + 1
-        user_lookup[id] = User(id, name)
-        return id
-
-    class UserContainerNode(object):
-        exposed = True
-
-        def POST(self, name):
-            """
-            Allow the creation of a new Object
-            """
-            return "POST %d" % make_user(name)
-
-        def GET(self):
-            keys = user_lookup.keys()
-            keys.sort()
-            return unicode(keys)
-
-        def dynamic_dispatch(self, vpath):
-            try:
-                id = int(vpath[0])
-            except ValueError:
-                return None
-            return UserInstanceNode(id)
-
-    class UserInstanceNode(object):
-        exposed = True
-        def __init__(self, id):
-            self.id = id
-            self.user = user_lookup.get(id, None)
-
-            # For all but PUT methods there MUST be a valid user identified
-            # by self.id
-            if not self.user and cherrypy.request.method != 'PUT':
-                raise cherrypy.HTTPError(404)
-
-        def GET(self, *args, **kwargs):
-            """
-            Return the appropriate representation of the instance.
-            """
-            return unicode(self.user)
-
-        def POST(self, name):
-            """
-            Update the fields of the user instance.
-            """
-            self.user.name = name
-            return "POST %d" % self.user.id
-
-        def PUT(self, name):
-            """
-            Create a new user with the specified id, or edit it if it already exists
-            """
-            if self.user:
-                # Edit the current user
-                self.user.name = name
-                return "PUT %d" % self.user.id
-            else:
-                # Make a new user with said attributes.
-                return "PUT %d" % make_user(name, self.id)
-
-        def DELETE(self):
-            """
-            Delete the user specified at the id.
-            """
-            id = self.user.id
-            del user_lookup[self.user.id]
-            del self.user
-            return "DELETE %d" % id
-
-
-    Root.users = UserContainerNode()
-
-    md = cherrypy.dispatch.MethodDispatcher('dynamic_dispatch')
-    for url in script_names:
-        conf = {'/': {
-                    'user': (url or "/").split("/")[-2],
-                },
-                '/users': {
-                    'request.dispatch': md
-                },
-            }
-        cherrypy.tree.mount(Root(), url, conf)
-
-
-from cherrypy.test import helper
-
-class DynamicObjectMappingTest(helper.CPWebCase):
-
-    def testObjectMapping(self):
-        for url in script_names:
-            prefix = self.script_name = url
-
-            self.getPage('/')
-            self.assertBody('index')
-
-            self.getPage('/handler')
-            self.assertBody('handler')
-
-            # Dynamic dispatch will succeed here for the subnodes
-            # so the subroot gets called
-            self.getPage('/1/')
-            self.assertBody('SubRoot index')
-
-            self.getPage('/2/')
-            self.assertBody('SubRoot index')
-
-            self.getPage('/1/handler')
-            self.assertBody('SubRoot handler')
-
-            self.getPage('/2/handler')
-            self.assertBody('SubRoot handler')
-
-            # Dynamic dispatch will fail here for the subnodes
-            # so the default gets called
-            self.getPage('/asdf/')
-            self.assertBody("default ('asdf',)")
-
-            self.getPage('/asdf/asdf')
-            self.assertBody("default ('asdf', 'asdf')")
-
-            self.getPage('/asdf/handler')
-            self.assertBody("default ('asdf', 'handler')")
-
-            # Dynamic dispatch will succeed here for the subsubnodes
-            # so the subsubroot gets called
-            self.getPage('/1/1/')
-            self.assertBody('SubSubRoot index')
-
-            self.getPage('/2/2/')
-            self.assertBody('SubSubRoot index')
-
-            self.getPage('/1/1/handler')
-            self.assertBody('SubSubRoot handler')
-
-            self.getPage('/2/2/handler')
-            self.assertBody('SubSubRoot handler')
-
-            self.getPage('/2/2/dispatch')
-            self.assertBody('SubSubRoot dispatch')
-
-            # The exposed dispatch will not be called as a dispatch
-            # method.
-            self.getPage('/2/2/foo/foo')
-            self.assertBody("SubSubRoot default")
-
-            # Dynamic dispatch will fail here for the subsubnodes
-            # so the SubRoot gets called
-            self.getPage('/1/asdf/')
-            self.assertBody("SubRoot ('asdf',)")
-
-            self.getPage('/1/asdf/asdf')
-            self.assertBody("SubRoot ('asdf', 'asdf')")
-
-            self.getPage('/1/asdf/handler')
-            self.assertBody("SubRoot ('asdf', 'handler')")
-
-    def testMethodDispatch(self):
-        # GET acts like a container
-        self.getPage("/users")
-        self.assertBody("[1, 2]")
-        self.assertHeader('Allow', 'GET, HEAD, POST')
-
-        # POST to the container URI allows creation
-        self.getPage("/users", method="POST", body="name=baz")
-        self.assertBody("POST 3")
-        self.assertHeader('Allow', 'GET, HEAD, POST')
-
-        # POST to a specific instanct URI results in a 404
-        # as the resource does not exit.
-        self.getPage("/users/5", method="POST", body="name=baz")
-        self.assertStatus(404)
-
-        # PUT to a specific instanct URI results in creation
-        self.getPage("/users/5", method="PUT", body="name=boris")
-        self.assertBody("PUT 5")
-        self.assertHeader('Allow', 'DELETE, GET, HEAD, POST, PUT')
-
-        # GET acts like a container
-        self.getPage("/users")
-        self.assertBody("[1, 2, 3, 5]")
-        self.assertHeader('Allow', 'GET, HEAD, POST')
-
-        test_cases = (
-            (1, 'foo', 'fooupdated', 'DELETE, GET, HEAD, POST, PUT'),
-            (2, 'bar', 'barupdated', 'DELETE, GET, HEAD, POST, PUT'),
-            (3, 'baz', 'bazupdated', 'DELETE, GET, HEAD, POST, PUT'),
-            (5, 'boris', 'borisupdated', 'DELETE, GET, HEAD, POST, PUT'),
-        )
-        for id, name, updatedname, headers in test_cases:
-            self.getPage("/users/%d" % id)
-            self.assertBody(name)
-            self.assertHeader('Allow', headers)
-
-            # Make sure POSTs update already existings resources
-            self.getPage("/users/%d" % id, method='POST', body="name=%s" % updatedname)
-            self.assertBody("POST %d" % id)
-            self.assertHeader('Allow', headers)
-
-            # Make sure PUTs Update already existing resources.
-            self.getPage("/users/%d" % id, method='PUT', body="name=%s" % updatedname)
-            self.assertBody("PUT %d" % id)
-            self.assertHeader('Allow', headers)
-
-            # Make sure DELETES Remove already existing resources.
-            self.getPage("/users/%d" % id, method='DELETE')
-            self.assertBody("DELETE %d" % id)
-            self.assertHeader('Allow', headers)
-
-
-        # GET acts like a container
-        self.getPage("/users")
-        self.assertBody("[]")
-        self.assertHeader('Allow', 'GET, HEAD, POST')
-
-if __name__ == "__main__":
-    helper.testmain()
--- a/bundled/cherrypy/cherrypy/test/test_encoding.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,345 +0,0 @@
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import gzip
-try:
-    from cStringIO import StringIO
-except ImportError:
-    from StringIO import StringIO
-from httplib import IncompleteRead
-import sys
-
-import cherrypy
-
-europoundUnicode = u'\x80\xa3'
-sing = u"\u6bdb\u6cfd\u4e1c: Sing, Little Birdie?"
-sing8 = sing.encode('utf-8')
-sing16 = sing.encode('utf-16')
-
-
-def setup_server():
-    class Root:
-        def index(self, param):
-            assert param == europoundUnicode, "%r != %r" % (param, europoundUnicode)
-            yield europoundUnicode
-        index.exposed = True
-        
-        def mao_zedong(self):
-            return sing
-        mao_zedong.exposed = True
-        
-        def utf8(self):
-            return sing8
-        utf8.exposed = True
-        utf8._cp_config = {'tools.encode.encoding': 'utf-8'}
-        
-        def reqparams(self, *args, **kwargs):
-            return ', '.join([": ".join((k, v)).encode('utf8')
-                              for k, v in cherrypy.request.params.items()])
-        reqparams.exposed = True
-    
-    class GZIP:
-        def index(self):
-            yield "Hello, world"
-        index.exposed = True
-        
-        def noshow(self):
-            # Test for ticket #147, where yield showed no exceptions (content-
-            # encoding was still gzip even though traceback wasn't zipped).
-            raise IndexError()
-            yield "Here be dragons"
-        noshow.exposed = True
-        # Turn encoding off so the gzip tool is the one doing the collapse.
-        noshow._cp_config = {'tools.encode.on': False}
-        
-        def noshow_stream(self):
-            # Test for ticket #147, where yield showed no exceptions (content-
-            # encoding was still gzip even though traceback wasn't zipped).
-            raise IndexError()
-            yield "Here be dragons"
-        noshow_stream.exposed = True
-        noshow_stream._cp_config = {'response.stream': True}
-    
-    class Decode:
-        def extra_charset(self, *args, **kwargs):
-            return ', '.join([": ".join((k, v)).encode('utf8')
-                              for k, v in cherrypy.request.params.items()])
-        extra_charset.exposed = True
-        extra_charset._cp_config = {
-            'tools.decode.on': True,
-            'tools.decode.default_encoding': [u'utf-16'],
-            }
-        
-        def force_charset(self, *args, **kwargs):
-            return ', '.join([": ".join((k, v)).encode('utf8')
-                              for k, v in cherrypy.request.params.items()])
-        force_charset.exposed = True
-        force_charset._cp_config = {
-            'tools.decode.on': True,
-            'tools.decode.encoding': u'utf-16',
-            }
-    
-    root = Root()
-    root.gzip = GZIP()
-    root.decode = Decode()
-    cherrypy.tree.mount(root, config={'/gzip': {'tools.gzip.on': True}})
-
-
-
-from cherrypy.test import helper
-
-
-class EncodingTests(helper.CPWebCase):
-    
-    def test_query_string_decoding(self):
-        europoundUtf8 = europoundUnicode.encode('utf-8')
-        self.getPage('/?param=' + europoundUtf8)
-        self.assertBody(europoundUtf8)
-        
-        # Encoded utf8 query strings MUST be parsed correctly.
-        # Here, q is the POUND SIGN U+00A3 encoded in utf8 and then %HEX
-        self.getPage("/reqparams?q=%C2%A3")
-        # The return value will be encoded as utf8.
-        self.assertBody("q: \xc2\xa3")
-        
-        # Query strings that are incorrectly encoded MUST raise 404.
-        # Here, q is the POUND SIGN U+00A3 encoded in latin1 and then %HEX
-        self.getPage("/reqparams?q=%A3")
-        self.assertStatus(404)
-        self.assertErrorPage(404, 
-            "The given query string could not be processed. Query "
-            "strings for this resource must be encoded with 'utf8'.")
-    
-    def test_urlencoded_decoding(self):
-        # Test the decoding of an application/x-www-form-urlencoded entity.
-        europoundUtf8 = europoundUnicode.encode('utf-8')
-        body="param=" + europoundUtf8
-        self.getPage('/', method='POST',
-                     headers=[("Content-Type", "application/x-www-form-urlencoded"),
-                              ("Content-Length", str(len(body))),
-                              ],
-                     body=body),
-        self.assertBody(europoundUtf8)
-        
-        # Encoded utf8 entities MUST be parsed and decoded correctly.
-        # Here, q is the POUND SIGN U+00A3 encoded in utf8
-        body = "q=\xc2\xa3"
-        self.getPage('/reqparams', method='POST',
-                     headers=[("Content-Type", "application/x-www-form-urlencoded"),
-                              ("Content-Length", str(len(body))),
-                              ],
-                     body=body),
-        self.assertBody("q: \xc2\xa3")
-        
-        # ...and in utf16, which is not in the default attempt_charsets list:
-        body = "\xff\xfeq\x00=\xff\xfe\xa3\x00"
-        self.getPage('/reqparams', method='POST',
-                     headers=[("Content-Type", "application/x-www-form-urlencoded;charset=utf-16"),
-                              ("Content-Length", str(len(body))),
-                              ],
-                     body=body),
-        self.assertBody("q: \xc2\xa3")
-        
-        # Entities that are incorrectly encoded MUST raise 400.
-        # Here, q is the POUND SIGN U+00A3 encoded in utf16, but
-        # the Content-Type incorrectly labels it utf-8.
-        body = "\xff\xfeq\x00=\xff\xfe\xa3\x00"
-        self.getPage('/reqparams', method='POST',
-                     headers=[("Content-Type", "application/x-www-form-urlencoded;charset=utf-8"),
-                              ("Content-Length", str(len(body))),
-                              ],
-                     body=body),
-        self.assertStatus(400)
-        self.assertErrorPage(400, 
-            "The request entity could not be decoded. The following charsets "
-            "were attempted: [u'utf-8']")
-    
-    def test_decode_tool(self):
-        # An extra charset should be tried first, and succeed if it matches.
-        # Here, we add utf-16 as a charset and pass a utf-16 body.
-        body = "\xff\xfeq\x00=\xff\xfe\xa3\x00"
-        self.getPage('/decode/extra_charset', method='POST',
-                     headers=[("Content-Type", "application/x-www-form-urlencoded"),
-                              ("Content-Length", str(len(body))),
-                              ],
-                     body=body),
-        self.assertBody("q: \xc2\xa3")
-        
-        # An extra charset should be tried first, and continue to other default
-        # charsets if it doesn't match.
-        # Here, we add utf-16 as a charset but still pass a utf-8 body.
-        body = "q=\xc2\xa3"
-        self.getPage('/decode/extra_charset', method='POST',
-                     headers=[("Content-Type", "application/x-www-form-urlencoded"),
-                              ("Content-Length", str(len(body))),
-                              ],
-                     body=body),
-        self.assertBody("q: \xc2\xa3")
-        
-        # An extra charset should error if force is True and it doesn't match.
-        # Here, we force utf-16 as a charset but still pass a utf-8 body.
-        body = "q=\xc2\xa3"
-        self.getPage('/decode/force_charset', method='POST',
-                     headers=[("Content-Type", "application/x-www-form-urlencoded"),
-                              ("Content-Length", str(len(body))),
-                              ],
-                     body=body),
-        self.assertErrorPage(400, 
-            "The request entity could not be decoded. The following charsets "
-            "were attempted: [u'utf-16']")
-    
-    def test_multipart_decoding(self):
-        # Test the decoding of a multipart entity when the charset (utf16) is
-        # explicitly given.
-        body='\r\n'.join(['--X',
-                          'Content-Type: text/plain;charset=utf-16',
-                          'Content-Disposition: form-data; name="text"',
-                          '',
-                          '\xff\xfea\x00b\x00\x1c c\x00',
-                          '--X',
-                          'Content-Type: text/plain;charset=utf-16',
-                          'Content-Disposition: form-data; name="submit"',
-                          '',
-                          '\xff\xfeC\x00r\x00e\x00a\x00t\x00e\x00',
-                          '--X--'])
-        self.getPage('/reqparams', method='POST',
-                     headers=[("Content-Type", "multipart/form-data;boundary=X"),
-                              ("Content-Length", str(len(body))),
-                              ],
-                     body=body),
-        self.assertBody("text: ab\xe2\x80\x9cc, submit: Create")
-    
-    def test_multipart_decoding_no_charset(self):
-        # Test the decoding of a multipart entity when the charset (utf8) is
-        # NOT explicitly given, but is in the list of charsets to attempt.
-        body='\r\n'.join(['--X',
-                          'Content-Disposition: form-data; name="text"',
-                          '',
-                          '\xe2\x80\x9c',
-                          '--X',
-                          'Content-Disposition: form-data; name="submit"',
-                          '',
-                          'Create',
-                          '--X--'])
-        self.getPage('/reqparams', method='POST',
-                     headers=[("Content-Type", "multipart/form-data;boundary=X"),
-                              ("Content-Length", str(len(body))),
-                              ],
-                     body=body),
-        self.assertBody("text: \xe2\x80\x9c, submit: Create")
-    
-    def test_multipart_decoding_no_successful_charset(self):
-        # Test the decoding of a multipart entity when the charset (utf16) is
-        # NOT explicitly given, and is NOT in the list of charsets to attempt.
-        body='\r\n'.join(['--X',
-                          'Content-Disposition: form-data; name="text"',
-                          '',
-                          '\xff\xfea\x00b\x00\x1c c\x00',
-                          '--X',
-                          'Content-Disposition: form-data; name="submit"',
-                          '',
-                          '\xff\xfeC\x00r\x00e\x00a\x00t\x00e\x00',
-                          '--X--'])
-        self.getPage('/reqparams', method='POST',
-                     headers=[("Content-Type", "multipart/form-data;boundary=X"),
-                              ("Content-Length", str(len(body))),
-                              ],
-                     body=body),
-        self.assertStatus(400)
-        self.assertErrorPage(400, 
-            "The request entity could not be decoded. The following charsets "
-            "were attempted: [u'us-ascii', u'utf-8']")
-    
-    def testEncoding(self):
-        # Default encoding should be utf-8
-        self.getPage('/mao_zedong')
-        self.assertBody(sing8)
-        
-        # Ask for utf-16.
-        self.getPage('/mao_zedong', [('Accept-Charset', 'utf-16')])
-        self.assertHeader('Content-Type', 'text/html;charset=utf-16')
-        self.assertBody(sing16)
-        
-        # Ask for multiple encodings. ISO-8859-1 should fail, and utf-16
-        # should be produced.
-        self.getPage('/mao_zedong', [('Accept-Charset',
-                                      'iso-8859-1;q=1, utf-16;q=0.5')])
-        self.assertBody(sing16)
-        
-        # The "*" value should default to our default_encoding, utf-8
-        self.getPage('/mao_zedong', [('Accept-Charset', '*;q=1, utf-7;q=.2')])
-        self.assertBody(sing8)
-        
-        # Only allow iso-8859-1, which should fail and raise 406.
-        self.getPage('/mao_zedong', [('Accept-Charset', 'iso-8859-1, *;q=0')])
-        self.assertStatus("406 Not Acceptable")
-        self.assertInBody("Your client sent this Accept-Charset header: "
-                          "iso-8859-1, *;q=0. We tried these charsets: "
-                          "iso-8859-1.")
-        
-        # Ask for x-mac-ce, which should be unknown. See ticket #569.
-        self.getPage('/mao_zedong', [('Accept-Charset',
-                                      'us-ascii, ISO-8859-1, x-mac-ce')])
-        self.assertStatus("406 Not Acceptable")
-        self.assertInBody("Your client sent this Accept-Charset header: "
-                          "us-ascii, ISO-8859-1, x-mac-ce. We tried these "
-                          "charsets: ISO-8859-1, us-ascii, x-mac-ce.")
-        
-        # Test the 'encoding' arg to encode.
-        self.getPage('/utf8')
-        self.assertBody(sing8)
-        self.getPage('/utf8', [('Accept-Charset', 'us-ascii, ISO-8859-1')])
-        self.assertStatus("406 Not Acceptable")
-    
-    def testGzip(self):
-        zbuf = StringIO()
-        zfile = gzip.GzipFile(mode='wb', fileobj=zbuf, compresslevel=9)
-        zfile.write("Hello, world")
-        zfile.close()
-        
-        self.getPage('/gzip/', headers=[("Accept-Encoding", "gzip")])
-        self.assertInBody(zbuf.getvalue()[:3])
-        self.assertHeader("Vary", "Accept-Encoding")
-        self.assertHeader("Content-Encoding", "gzip")
-        
-        # Test when gzip is denied.
-        self.getPage('/gzip/', headers=[("Accept-Encoding", "identity")])
-        self.assertHeader("Vary", "Accept-Encoding")
-        self.assertNoHeader("Content-Encoding")
-        self.assertBody("Hello, world")
-        
-        self.getPage('/gzip/', headers=[("Accept-Encoding", "gzip;q=0")])
-        self.assertHeader("Vary", "Accept-Encoding")
-        self.assertNoHeader("Content-Encoding")
-        self.assertBody("Hello, world")
-        
-        self.getPage('/gzip/', headers=[("Accept-Encoding", "*;q=0")])
-        self.assertStatus(406)
-        self.assertNoHeader("Content-Encoding")
-        self.assertErrorPage(406, "identity, gzip")
-        
-        # Test for ticket #147
-        self.getPage('/gzip/noshow', headers=[("Accept-Encoding", "gzip")])
-        self.assertNoHeader('Content-Encoding')
-        self.assertStatus(500)
-        self.assertErrorPage(500, pattern="IndexError\n")
-        
-        # In this case, there's nothing we can do to deliver a
-        # readable page, since 1) the gzip header is already set,
-        # and 2) we may have already written some of the body.
-        # The fix is to never stream yields when using gzip.
-        if (cherrypy.server.protocol_version == "HTTP/1.0" or
-            getattr(cherrypy.server, "using_apache", False)):
-            self.getPage('/gzip/noshow_stream',
-                         headers=[("Accept-Encoding", "gzip")])
-            self.assertHeader('Content-Encoding', 'gzip')
-            self.assertInBody('\x1f\x8b\x08\x00')
-        else:
-            # The wsgiserver will simply stop sending data, and the HTTP client
-            # will error due to an incomplete chunk-encoded stream.
-            self.assertRaises((ValueError, IncompleteRead), self.getPage,
-                              '/gzip/noshow_stream',
-                              headers=[("Accept-Encoding", "gzip")])
-
-if __name__ == "__main__":
-    helper.testmain()
--- a/bundled/cherrypy/cherrypy/test/test_etags.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import cherrypy
-
-
-def setup_server():
-    class Root:
-        def resource(self):
-            return "Oh wah ta goo Siam."
-        resource.exposed = True
-        
-        def fail(self, code):
-            code = int(code)
-            if 300 <= code <= 399:
-                raise cherrypy.HTTPRedirect([], code)
-            else:
-                raise cherrypy.HTTPError(code)
-        fail.exposed = True
-        
-        def unicoded(self):
-            return u'I am a \u1ee4nicode string.'
-        unicoded.exposed = True
-        unicoded._cp_config = {'tools.encode.on': True}
-    
-    conf = {'/': {'tools.etags.on': True,
-                  'tools.etags.autotags': True,
-                  }}
-    cherrypy.tree.mount(Root(), config=conf)
-
-from cherrypy.test import helper
-
-class ETagTest(helper.CPWebCase):
-    
-    def test_etags(self):
-        self.getPage("/resource")
-        self.assertStatus('200 OK')
-        self.assertHeader('Content-Type', 'text/html;charset=utf-8')
-        self.assertBody('Oh wah ta goo Siam.')
-        etag = self.assertHeader('ETag')
-        
-        # Test If-Match (both valid and invalid)
-        self.getPage("/resource", headers=[('If-Match', etag)])
-        self.assertStatus("200 OK")
-        self.getPage("/resource", headers=[('If-Match', "*")])
-        self.assertStatus("200 OK")
-        self.getPage("/resource", headers=[('If-Match', "*")], method="POST")
-        self.assertStatus("200 OK")
-        self.getPage("/resource", headers=[('If-Match', "a bogus tag")])
-        self.assertStatus("412 Precondition Failed")
-        
-        # Test If-None-Match (both valid and invalid)
-        self.getPage("/resource", headers=[('If-None-Match', etag)])
-        self.assertStatus(304)
-        self.getPage("/resource", method='POST', headers=[('If-None-Match', etag)])
-        self.assertStatus("412 Precondition Failed")
-        self.getPage("/resource", headers=[('If-None-Match', "*")])
-        self.assertStatus(304)
-        self.getPage("/resource", headers=[('If-None-Match', "a bogus tag")])
-        self.assertStatus("200 OK")
-    
-    def test_errors(self):
-        self.getPage("/resource")
-        self.assertStatus(200)
-        etag = self.assertHeader('ETag')
-        
-        # Test raising errors in page handler
-        self.getPage("/fail/412", headers=[('If-Match', etag)])
-        self.assertStatus(412)
-        self.getPage("/fail/304", headers=[('If-Match', etag)])
-        self.assertStatus(304)
-        self.getPage("/fail/412", headers=[('If-None-Match', "*")])
-        self.assertStatus(412)
-        self.getPage("/fail/304", headers=[('If-None-Match', "*")])
-        self.assertStatus(304)
-    
-    def test_unicode_body(self):
-        self.getPage("/unicoded")
-        self.assertStatus(200)
-        etag1 = self.assertHeader('ETag')
-        self.getPage("/unicoded", headers=[('If-Match', etag1)])
-        self.assertStatus(200)
-        self.assertHeader('ETag', etag1)
-
-
-if __name__ == "__main__":
-    helper.testmain()
--- a/bundled/cherrypy/cherrypy/test/test_http.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,182 +0,0 @@
-"""Tests for managing HTTP issues (malformed requests, etc)."""
-
-from cherrypy.test import test
-test.prefer_parent_path()
-
-from httplib import HTTPConnection, HTTPSConnection
-import cherrypy
-import mimetypes
-
-
-def encode_multipart_formdata(files):
-    """Return (content_type, body) ready for httplib.HTTP instance.
-    
-    files: a sequence of (name, filename, value) tuples for multipart uploads.
-    """
-    BOUNDARY = '________ThIs_Is_tHe_bouNdaRY_$'
-    L = []
-    for key, filename, value in files:
-        L.append('--' + BOUNDARY)
-        L.append('Content-Disposition: form-data; name="%s"; filename="%s"' %
-                 (key, filename))
-        ct = mimetypes.guess_type(filename)[0] or 'application/octet-stream'
-        L.append('Content-Type: %s' % ct)
-        L.append('')
-        L.append(value)
-    L.append('--' + BOUNDARY + '--')
-    L.append('')
-    body = '\r\n'.join(L)
-    content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
-    return content_type, body
-
-
-def setup_server():
-    
-    class Root:
-        def index(self, *args, **kwargs):
-            return "Hello world!"
-        index.exposed = True
-        
-        def no_body(self, *args, **kwargs):
-            return "Hello world!"
-        no_body.exposed = True
-        no_body._cp_config = {'request.process_request_body': False}
-        
-        def post_multipart(self, file):
-            """Return a summary ("a * 65536\nb * 65536") of the uploaded file."""
-            contents = file.file.read()
-            summary = []
-            curchar = ""
-            count = 0
-            for c in contents:
-                if c == curchar:
-                    count += 1
-                else:
-                    if count:
-                        summary.append("%s * %d" % (curchar, count))
-                    count = 1
-                    curchar = c
-            if count:
-                summary.append("%s * %d" % (curchar, count))
-            return ", ".join(summary)
-        post_multipart.exposed = True
-    
-    cherrypy.tree.mount(Root())
-    cherrypy.config.update({'server.max_request_body_size': 30000000})
-
-
-from cherrypy.test import helper
-
-class HTTPTests(helper.CPWebCase):
-    
-    def test_no_content_length(self):
-        # "The presence of a message-body in a request is signaled by the
-        # inclusion of a Content-Length or Transfer-Encoding header field in
-        # the request's message-headers."
-        # 
-        # Send a message with neither header and no body. Even though
-        # the request is of method POST, this should be OK because we set
-        # request.process_request_body to False for our handler.
-        if self.scheme == "https":
-            c = HTTPSConnection('%s:%s' % (self.interface(), self.PORT))
-        else:
-            c = HTTPConnection('%s:%s' % (self.interface(), self.PORT))
-        c.request("POST", "/no_body")
-        response = c.getresponse()
-        self.body = response.fp.read()
-        self.status = str(response.status)
-        self.assertStatus(200)
-        self.assertBody('Hello world!')
-        
-        # Now send a message that has no Content-Length, but does send a body.
-        # Verify that CP times out the socket and responds
-        # with 411 Length Required.
-        if self.scheme == "https":
-            c = HTTPSConnection('%s:%s' % (self.interface(), self.PORT))
-        else:
-            c = HTTPConnection('%s:%s' % (self.interface(), self.PORT))
-        c.request("POST", "/")
-        response = c.getresponse()
-        self.body = response.fp.read()
-        self.status = str(response.status)
-        self.assertStatus(411)
-    
-    def test_post_multipart(self):
-        alphabet = "abcdefghijklmnopqrstuvwxyz"
-        # generate file contents for a large post
-        contents = "".join([c * 65536 for c in alphabet])
-        
-        # encode as multipart form data
-        files=[('file', 'file.txt', contents)]
-        content_type, body = encode_multipart_formdata(files)
-        
-        # post file
-        if self.scheme == 'https':
-            c = HTTPSConnection('%s:%s' % (self.interface(), self.PORT))
-        else:
-            c = HTTPConnection('%s:%s' % (self.interface(), self.PORT))
-        c.putrequest('POST', '/post_multipart')
-        c.putheader('Content-Type', content_type)
-        c.putheader('Content-Length', str(len(body)))
-        c.endheaders()
-        c.send(body)
-        
-        response = c.getresponse()
-        self.body = response.fp.read()
-        self.status = str(response.status)
-        self.assertStatus(200)
-        self.assertBody(", ".join(["%s * 65536" % c for c in alphabet]))
-
-    def test_malformed_request_line(self):
-        if getattr(cherrypy.server, "using_apache", False):
-            return self.skip("skipped due to known Apache differences...")
-        
-        # Test missing version in Request-Line
-        if self.scheme == 'https':
-            c = HTTPSConnection('%s:%s' % (self.interface(), self.PORT))
-        else:
-            c = HTTPConnection('%s:%s' % (self.interface(), self.PORT))
-        c._output('GET /')
-        c._send_output()
-        response = c.response_class(c.sock, strict=c.strict, method='GET')
-        response.begin()
-        self.assertEqual(response.status, 400)
-        self.assertEqual(response.fp.read(22), "Malformed Request-Line")
-        c.close()
-    
-    def test_malformed_header(self):
-        if self.scheme == 'https':
-            c = HTTPSConnection('%s:%s' % (self.interface(), self.PORT))
-        else:
-            c = HTTPConnection('%s:%s' % (self.interface(), self.PORT))
-        c.putrequest('GET', '/')
-        c.putheader('Content-Type', 'text/plain')
-        # See http://www.cherrypy.org/ticket/941 
-        c._output('Re, 1.2.3.4#015#012')
-        c.endheaders()
-        
-        response = c.getresponse()
-        self.status = str(response.status)
-        self.assertStatus(400)
-        self.body = response.fp.read()
-        self.assertBody("Illegal header line.")
-    
-    def test_http_over_https(self):
-        if self.scheme != 'https':
-            return self.skip("skipped (not running HTTPS)... ")
-        
-        # Try connecting without SSL.
-        conn = HTTPConnection('%s:%s' % (self.interface(), self.PORT))
-        conn.putrequest("GET", "/", skip_host=True)
-        conn.putheader("Host", self.HOST)
-        conn.endheaders()
-        response = conn.response_class(conn.sock, method="GET")
-        response.begin()
-        self.assertEqual(response.status, 400)
-        self.body = response.read()
-        self.assertBody("The client sent a plain HTTP request, but this "
-                        "server only speaks HTTPS on this port.")
-
-
-if __name__ == '__main__':
-    helper.testmain()
--- a/bundled/cherrypy/cherrypy/test/test_httpauth.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-from cherrypy.test import test
-test.prefer_parent_path()
-
-try:
-    # Python 2.5+
-    from hashlib import md5, sha1 as sha
-except ImportError:
-    from md5 import new as md5
-    from sha import new as sha
-
-import cherrypy
-from cherrypy.lib import httpauth
-
-def setup_server():
-    class Root:
-        def index(self):
-            return "This is public."
-        index.exposed = True
-
-    class DigestProtected:
-        def index(self):
-            return "Hello %s, you've been authorized." % cherrypy.request.login
-        index.exposed = True
-
-    class BasicProtected:
-        def index(self):
-            return "Hello %s, you've been authorized." % cherrypy.request.login
-        index.exposed = True
-
-    class BasicProtected2:
-        def index(self):
-            return "Hello %s, you've been authorized." % cherrypy.request.login
-        index.exposed = True
-
-    def fetch_users():
-        return {'test': 'test'}
-
-    def sha_password_encrypter(password):
-        return sha(password).hexdigest()
-    
-    def fetch_password(username):
-        return sha('test').hexdigest()
-
-    conf = {'/digest': {'tools.digest_auth.on': True,
-                        'tools.digest_auth.realm': 'localhost',
-                        'tools.digest_auth.users': fetch_users},
-            '/basic': {'tools.basic_auth.on': True,
-                       'tools.basic_auth.realm': 'localhost',
-                       'tools.basic_auth.users': {'test': md5('test').hexdigest()}},
-            '/basic2': {'tools.basic_auth.on': True,
-                        'tools.basic_auth.realm': 'localhost',
-                        'tools.basic_auth.users': fetch_password,
-                        'tools.basic_auth.encrypt': sha_password_encrypter}}
-            
-    root = Root()
-    root.digest = DigestProtected()
-    root.basic = BasicProtected()
-    root.basic2 = BasicProtected2()
-    cherrypy.tree.mount(root, config=conf)
-
-from cherrypy.test import helper
-
-class HTTPAuthTest(helper.CPWebCase):
-
-    def testPublic(self):
-        self.getPage("/")
-        self.assertStatus('200 OK')
-        self.assertHeader('Content-Type', 'text/html;charset=utf-8')
-        self.assertBody('This is public.')
-
-    def testBasic(self):
-        self.getPage("/basic/")
-        self.assertStatus(401)
-        self.assertHeader('WWW-Authenticate', 'Basic realm="localhost"')
-
-        self.getPage('/basic/', [('Authorization', 'Basic dGVzdDp0ZX60')])
-        self.assertStatus(401)
-        
-        self.getPage('/basic/', [('Authorization', 'Basic dGVzdDp0ZXN0')])
-        self.assertStatus('200 OK')
-        self.assertBody("Hello test, you've been authorized.")
-
-    def testBasic2(self):
-        self.getPage("/basic2/")
-        self.assertStatus(401)
-        self.assertHeader('WWW-Authenticate', 'Basic realm="localhost"')
-
-        self.getPage('/basic2/', [('Authorization', 'Basic dGVzdDp0ZX60')])
-        self.assertStatus(401)
-        
-        self.getPage('/basic2/', [('Authorization', 'Basic dGVzdDp0ZXN0')])
-        self.assertStatus('200 OK')
-        self.assertBody("Hello test, you've been authorized.")
-
-    def testDigest(self):
-        self.getPage("/digest/")
-        self.assertStatus(401)
-        
-        value = None
-        for k, v in self.headers:
-            if k.lower() == "www-authenticate":
-                if v.startswith("Digest"):
-                    value = v
-                    break
-
-        if value is None:
-            self._handlewebError("Digest authentification scheme was not found")
-
-        value = value[7:]
-        items = value.split(', ')
-        tokens = {}
-        for item in items:
-            key, value = item.split('=')
-            tokens[key.lower()] = value
-            
-        missing_msg = "%s is missing"
-        bad_value_msg = "'%s' was expecting '%s' but found '%s'"
-        nonce = None
-        if 'realm' not in tokens:
-            self._handlewebError(missing_msg % 'realm')
-        elif tokens['realm'] != '"localhost"':
-            self._handlewebError(bad_value_msg % ('realm', '"localhost"', tokens['realm']))
-        if 'nonce' not in tokens:
-            self._handlewebError(missing_msg % 'nonce')
-        else:
-            nonce = tokens['nonce'].strip('"')
-        if 'algorithm' not in tokens:
-            self._handlewebError(missing_msg % 'algorithm')
-        elif tokens['algorithm'] != '"MD5"':
-            self._handlewebError(bad_value_msg % ('algorithm', '"MD5"', tokens['algorithm']))
-        if 'qop' not in tokens:
-            self._handlewebError(missing_msg % 'qop')
-        elif tokens['qop'] != '"auth"':
-            self._handlewebError(bad_value_msg % ('qop', '"auth"', tokens['qop']))
-
-        # Test a wrong 'realm' value
-        base_auth = 'Digest username="test", realm="wrong realm", nonce="%s", uri="/digest/", algorithm=MD5, response="%s", qop=auth, nc=%s, cnonce="1522e61005789929"'
-
-        auth = base_auth % (nonce, '', '00000001')
-        params = httpauth.parseAuthorization(auth)
-        response = httpauth._computeDigestResponse(params, 'test')
-        
-        auth = base_auth % (nonce, response, '00000001')
-        self.getPage('/digest/', [('Authorization', auth)])
-        self.assertStatus(401)
-
-        # Test that must pass
-        base_auth = 'Digest username="test", realm="localhost", nonce="%s", uri="/digest/", algorithm=MD5, response="%s", qop=auth, nc=%s, cnonce="1522e61005789929"'
-
-        auth = base_auth % (nonce, '', '00000001')
-        params = httpauth.parseAuthorization(auth)
-        response = httpauth._computeDigestResponse(params, 'test')
-        
-        auth = base_auth % (nonce, response, '00000001')
-        self.getPage('/digest/', [('Authorization', auth)])
-        self.assertStatus('200 OK')
-        self.assertBody("Hello test, you've been authorized.")
-            
-if __name__ == "__main__":
-    helper.testmain()
--- a/bundled/cherrypy/cherrypy/test/test_httplib.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-"""Tests for cherrypy/lib/httputil.py."""
-
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import unittest
-from cherrypy.lib import httputil
-
-
-class UtilityTests(unittest.TestCase):
-    
-    def test_urljoin(self):
-        # Test all slash+atom combinations for SCRIPT_NAME and PATH_INFO
-        self.assertEqual(httputil.urljoin("/sn/", "/pi/"), "/sn/pi/")
-        self.assertEqual(httputil.urljoin("/sn/", "/pi"), "/sn/pi")
-        self.assertEqual(httputil.urljoin("/sn/", "/"), "/sn/")
-        self.assertEqual(httputil.urljoin("/sn/", ""), "/sn/")
-        self.assertEqual(httputil.urljoin("/sn", "/pi/"), "/sn/pi/")
-        self.assertEqual(httputil.urljoin("/sn", "/pi"), "/sn/pi")
-        self.assertEqual(httputil.urljoin("/sn", "/"), "/sn/")
-        self.assertEqual(httputil.urljoin("/sn", ""), "/sn")
-        self.assertEqual(httputil.urljoin("/", "/pi/"), "/pi/")
-        self.assertEqual(httputil.urljoin("/", "/pi"), "/pi")
-        self.assertEqual(httputil.urljoin("/", "/"), "/")
-        self.assertEqual(httputil.urljoin("/", ""), "/")
-        self.assertEqual(httputil.urljoin("", "/pi/"), "/pi/")
-        self.assertEqual(httputil.urljoin("", "/pi"), "/pi")
-        self.assertEqual(httputil.urljoin("", "/"), "/")
-        self.assertEqual(httputil.urljoin("", ""), "/")
-
-if __name__ == '__main__':
-    unittest.main()
--- a/bundled/cherrypy/cherrypy/test/test_json.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-from cherrypy.test import test, helper
-test.prefer_parent_path()
-
-import cherrypy
-
-from cherrypy.lib.jsontools import json
-if json is None:
-    print "skipped (simplejson not found) "
-else:
-    def setup_server():
-        class Root(object):
-            def plain(self):
-                return 'hello'
-            plain.exposed = True
-
-            def json_string(self):
-                return 'hello'
-            json_string.exposed = True
-            json_string._cp_config = {'tools.json_out.on': True}
-
-            def json_list(self):
-                return ['a', 'b', 42]
-            json_list.exposed = True
-            json_list._cp_config = {'tools.json_out.on': True}
-
-            def json_dict(self):
-                return {'answer': 42}
-            json_dict.exposed = True
-            json_dict._cp_config = {'tools.json_out.on': True}
-
-            def json_post(self):
-                if cherrypy.request.json == [13, 'c']:
-                    return 'ok'
-                else:
-                    return 'nok'
-            json_post.exposed = True
-            json_post._cp_config = {'tools.json_in.on': True}
-
-        root = Root()
-        cherrypy.tree.mount(root)
-
-    class JsonTest(helper.CPWebCase):
-        def test_json_output(self):
-            self.getPage("/plain")
-            self.assertBody("hello")
-
-            self.getPage("/json_string")
-            self.assertBody('"hello"')
-
-            self.getPage("/json_list")
-            self.assertBody('["a", "b", 42]')
-
-            self.getPage("/json_dict")
-            self.assertBody('{"answer": 42}')
-
-        def test_json_input(self):
-            body = '[13, "c"]'
-            headers = [('Content-Type', 'application/json'),
-                       ('Content-Length', str(len(body)))]
-            self.getPage("/json_post", method="POST", headers=headers, body=body)
-            self.assertBody('ok')
-            
-            body = '[13, "c"]'
-            headers = [('Content-Type', 'text/plain'),
-                       ('Content-Length', str(len(body)))]
-            self.getPage("/json_post", method="POST", headers=headers, body=body)
-            self.assertStatus(415, 'Expected an application/json content type')
-            
-            body = '[13, -]'
-            headers = [('Content-Type', 'application/json'),
-                       ('Content-Length', str(len(body)))]
-            self.getPage("/json_post", method="POST", headers=headers, body=body)
-            self.assertStatus(400, 'Invalid JSON document')
-
-if __name__ == '__main__':
-    helper.testmain()
-
--- a/bundled/cherrypy/cherrypy/test/test_logging.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,153 +0,0 @@
-"""Basic tests for the CherryPy core: request handling."""
-
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import os
-localDir = os.path.dirname(__file__)
-
-import cherrypy
-
-access_log = os.path.join(localDir, "access.log")
-error_log = os.path.join(localDir, "error.log")
-
-# Some unicode strings.
-tartaros = u'\u03a4\u1f71\u03c1\u03c4\u03b1\u03c1\u03bf\u03c2'
-erebos = u'\u0388\u03c1\u03b5\u03b2\u03bf\u03c2.com'
-
-
-def setup_server():
-    class Root:
-        
-        def index(self):
-            return "hello"
-        index.exposed = True
-        
-        def uni_code(self):
-            cherrypy.request.login = tartaros
-            cherrypy.request.remote.name = erebos
-        uni_code.exposed = True
-        
-        def slashes(self):
-            cherrypy.request.request_line = r'GET /slashed\path HTTP/1.1'
-        slashes.exposed = True
-        
-        def whitespace(self):
-            # User-Agent = "User-Agent" ":" 1*( product | comment )
-            # comment    = "(" *( ctext | quoted-pair | comment ) ")"
-            # ctext      = <any TEXT excluding "(" and ")">
-            # TEXT       = <any OCTET except CTLs, but including LWS>
-            # LWS        = [CRLF] 1*( SP | HT )
-            cherrypy.request.headers['User-Agent'] = 'Browzuh (1.0\r\n\t\t.3)'
-        whitespace.exposed = True
-        
-        def as_string(self):
-            return "content"
-        as_string.exposed = True
-        
-        def as_yield(self):
-            yield "content"
-        as_yield.exposed = True
-        
-        def error(self):
-            raise ValueError()
-        error.exposed = True
-        error._cp_config = {'tools.log_tracebacks.on': True}
-    
-    root = Root()
-
-
-    cherrypy.config.update({'log.error_file': error_log,
-                            'log.access_file': access_log,
-                            })
-    cherrypy.tree.mount(root)
-
-
-
-from cherrypy.test import helper, logtest
-
-class AccessLogTests(helper.CPWebCase, logtest.LogCase):
-    
-    logfile = access_log
-    
-    def testNormalReturn(self):
-        self.markLog()
-        self.getPage("/as_string",
-                     headers=[('Referer', 'http://www.cherrypy.org/'),
-                              ('User-Agent', 'Mozilla/5.0')])
-        self.assertBody('content')
-        self.assertStatus(200)
-        
-        intro = '%s - - [' % self.interface()
-        
-        self.assertLog(-1, intro)
-        
-        if [k for k, v in self.headers if k.lower() == 'content-length']:
-            self.assertLog(-1, '] "GET %s/as_string HTTP/1.1" 200 7 '
-                           '"http://www.cherrypy.org/" "Mozilla/5.0"'
-                           % self.prefix())
-        else:
-            self.assertLog(-1, '] "GET %s/as_string HTTP/1.1" 200 - '
-                           '"http://www.cherrypy.org/" "Mozilla/5.0"'
-                           % self.prefix())
-    
-    def testNormalYield(self):
-        self.markLog()
-        self.getPage("/as_yield")
-        self.assertBody('content')
-        self.assertStatus(200)
-        
-        intro = '%s - - [' % self.interface()
-        
-        self.assertLog(-1, intro)
-        if [k for k, v in self.headers if k.lower() == 'content-length']:
-            self.assertLog(-1, '] "GET %s/as_yield HTTP/1.1" 200 7 "" ""' %
-                           self.prefix())
-        else:
-            self.assertLog(-1, '] "GET %s/as_yield HTTP/1.1" 200 - "" ""'
-                           % self.prefix())
-    
-    def testEscapedOutput(self):
-        # Test unicode in access log pieces.
-        self.markLog()
-        self.getPage("/uni_code")
-        self.assertStatus(200)
-        self.assertLog(-1, repr(tartaros.encode('utf8'))[1:-1])
-        # Test the erebos value. Included inline for your enlightenment.
-        # Note the 'r' prefix--those backslashes are literals.
-        self.assertLog(-1, r'\xce\x88\xcf\x81\xce\xb5\xce\xb2\xce\xbf\xcf\x82')
-        
-        # Test backslashes in output.
-        self.markLog()
-        self.getPage("/slashes")
-        self.assertStatus(200)
-        self.assertLog(-1, r'"GET /slashed\\path HTTP/1.1"')
-        
-        # Test whitespace in output.
-        self.markLog()
-        self.getPage("/whitespace")
-        self.assertStatus(200)
-        # Again, note the 'r' prefix.
-        self.assertLog(-1, r'"Browzuh (1.0\r\n\t\t.3)"')
-
-
-class ErrorLogTests(helper.CPWebCase, logtest.LogCase):
-    
-    logfile = error_log
-    
-    def testTracebacks(self):
-        # Test that tracebacks get written to the error log.
-        self.markLog()
-        ignore = helper.webtest.ignored_exceptions
-        ignore.append(ValueError)
-        try:
-            self.getPage("/error")
-            self.assertInBody("raise ValueError()")
-            self.assertLog(0, 'HTTP Traceback (most recent call last):')
-            self.assertLog(-3, 'raise ValueError()')
-        finally:
-            ignore.pop()
-
-
-if __name__ == '__main__':
-    helper.testmain()
--- a/bundled/cherrypy/cherrypy/test/test_mime.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,105 +0,0 @@
-"""Tests for various MIME issues, including the safe_multipart Tool."""
-
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import cherrypy
-
-
-def setup_server():
-    
-    class Root:
-        
-        def multipart(self, parts):
-            return repr(parts)
-        multipart.exposed = True
-        
-        def flashupload(self, Filedata, Upload, Filename):
-            return ("Upload: %r, Filename: %r, Filedata: %r" %
-                    (Upload, Filename, Filedata.file.read()))
-        flashupload.exposed = True
-    
-    cherrypy.config.update({'server.max_request_body_size': 0})
-    cherrypy.tree.mount(Root())
-
-
-#                             Client-side code                             #
-
-from cherrypy.test import helper
-
-class MultipartTest(helper.CPWebCase):
-    
-    def test_multipart(self):
-        text_part = u"This is the text version"
-        html_part = u"""<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<html>
-<head>
- <meta content="text/html;charset=ISO-8859-1" http-equiv="Content-Type">
-</head>
-<body bgcolor="#ffffff" text="#000000">
-
-This is the <strong>HTML</strong> version
-</body>
-</html>
-"""
-        body = '\r\n'.join([
-            "--123456789",
-            "Content-Type: text/plain; charset='ISO-8859-1'",
-            "Content-Transfer-Encoding: 7bit",
-            "",
-            text_part,
-            "--123456789",
-            "Content-Type: text/html; charset='ISO-8859-1'",
-            "",
-            html_part,
-            "--123456789--"])
-        headers = [
-            ('Content-Type', 'multipart/mixed; boundary=123456789'),
-            ('Content-Length', len(body)),
-            ]
-        self.getPage('/multipart', headers, "POST", body)
-        self.assertBody(repr([text_part, html_part]))
-
-
-class SafeMultipartHandlingTest(helper.CPWebCase):
-    
-    def test_Flash_Upload(self):
-        headers = [
-            ('Accept', 'text/*'),
-            ('Content-Type', 'multipart/form-data; '
-                 'boundary=----------KM7Ij5cH2KM7Ef1gL6ae0ae0cH2gL6'),
-            ('User-Agent', 'Shockwave Flash'),
-            ('Host', 'www.example.com:8080'),
-            ('Content-Length', '499'),
-            ('Connection', 'Keep-Alive'),
-            ('Cache-Control', 'no-cache'),
-            ]
-        filedata = ('<?xml version="1.0" encoding="UTF-8"?>\r\n'
-                    '<projectDescription>\r\n'
-                    '</projectDescription>\r\n')
-        body = (
-            '------------KM7Ij5cH2KM7Ef1gL6ae0ae0cH2gL6\r\n'
-            'Content-Disposition: form-data; name="Filename"\r\n'
-            '\r\n'
-            '.project\r\n'
-            '------------KM7Ij5cH2KM7Ef1gL6ae0ae0cH2gL6\r\n'
-            'Content-Disposition: form-data; '
-                'name="Filedata"; filename=".project"\r\n'
-            'Content-Type: application/octet-stream\r\n'
-            '\r\n'
-            + filedata + 
-            '\r\n'
-            '------------KM7Ij5cH2KM7Ef1gL6ae0ae0cH2gL6\r\n'
-            'Content-Disposition: form-data; name="Upload"\r\n'
-            '\r\n'
-            'Submit Query\r\n'
-            # Flash apps omit the trailing \r\n on the last line:
-            '------------KM7Ij5cH2KM7Ef1gL6ae0ae0cH2gL6--'
-            )
-        self.getPage('/flashupload', headers, "POST", body)
-        self.assertBody("Upload: u'Submit Query', Filename: u'.project', "
-                        "Filedata: %r" % filedata)
-
-
-if __name__ == '__main__':
-    helper.testmain()
--- a/bundled/cherrypy/cherrypy/test/test_misc_tools.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,204 +0,0 @@
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import os
-localDir = os.path.dirname(__file__)
-logfile = os.path.join(localDir, "test_misc_tools.log")
-
-import cherrypy
-from cherrypy import tools
-
-
-def setup_server():
-    class Root:
-        def index(self):
-            yield "Hello, world"
-        index.exposed = True
-        h = [("Content-Language", "en-GB"), ('Content-Type', 'text/plain')]
-        tools.response_headers(headers=h)(index)
-        
-        def other(self):
-            return "salut"
-        other.exposed = True
-        other._cp_config = {
-            'tools.response_headers.on': True,
-            'tools.response_headers.headers': [("Content-Language", "fr"),
-                                               ('Content-Type', 'text/plain')],
-            'tools.log_hooks.on': True,
-            }
-    
-    
-    class Accept:
-        _cp_config = {'tools.accept.on': True}
-        
-        def index(self):
-            return '<a href="feed">Atom feed</a>'
-        index.exposed = True
-        
-        # In Python 2.4+, we could use a decorator instead:
-        # @tools.accept('application/atom+xml')
-        def feed(self):
-            return """<?xml version="1.0" encoding="utf-8"?>
-<feed xmlns="http://www.w3.org/2005/Atom">
-    <title>Unknown Blog</title>
-</feed>"""
-        feed.exposed = True
-        feed._cp_config = {'tools.accept.media': 'application/atom+xml'}
-        
-        def select(self):
-            # We could also write this: mtype = cherrypy.lib.accept.accept(...)
-            mtype = tools.accept.callable(['text/html', 'text/plain'])
-            if mtype == 'text/html':
-                return "<h2>Page Title</h2>"
-            else:
-                return "PAGE TITLE"
-        select.exposed = True
-    
-    class Referer:
-        def accept(self):
-            return "Accepted!"
-        accept.exposed = True
-        reject = accept
-    
-    class AutoVary:
-        def index(self):
-            # Read a header directly with 'get'
-            ae = cherrypy.request.headers.get('Accept-Encoding')
-            # Read a header directly with '__getitem__'
-            cl = cherrypy.request.headers['Host']
-            # Read a header directly with '__contains__'
-            hasif = 'If-Modified-Since' in cherrypy.request.headers
-            # Read a header directly with 'has_key'
-            has = cherrypy.request.headers.has_key('Range')
-            # Call a lib function
-            mtype = tools.accept.callable(['text/html', 'text/plain'])
-            return "Hello, world!"
-        index.exposed = True
-    
-    conf = {'/referer': {'tools.referer.on': True,
-                         'tools.referer.pattern': r'http://[^/]*example\.com',
-                         },
-            '/referer/reject': {'tools.referer.accept': False,
-                                'tools.referer.accept_missing': True,
-                                },
-            '/autovary': {'tools.autovary.on': True},
-            }
-    
-    root = Root()
-    root.referer = Referer()
-    root.accept = Accept()
-    root.autovary = AutoVary()
-    cherrypy.tree.mount(root, config=conf)
-    cherrypy.config.update({'log.error_file': logfile})
-
-
-from cherrypy.test import helper
-
-class ResponseHeadersTest(helper.CPWebCase):
-
-    def testResponseHeadersDecorator(self):
-        self.getPage('/')
-        self.assertHeader("Content-Language", "en-GB")
-        self.assertHeader('Content-Type', 'text/plain;charset=utf-8')
-
-    def testResponseHeaders(self):
-        self.getPage('/other')
-        self.assertHeader("Content-Language", "fr")
-        self.assertHeader('Content-Type', 'text/plain;charset=utf-8')
-
-
-class RefererTest(helper.CPWebCase):
-    
-    def testReferer(self):
-        self.getPage('/referer/accept')
-        self.assertErrorPage(403, 'Forbidden Referer header.')
-        
-        self.getPage('/referer/accept',
-                     headers=[('Referer', 'http://www.example.com/')])
-        self.assertStatus(200)
-        self.assertBody('Accepted!')
-        
-        # Reject
-        self.getPage('/referer/reject')
-        self.assertStatus(200)
-        self.assertBody('Accepted!')
-        
-        self.getPage('/referer/reject',
-                     headers=[('Referer', 'http://www.example.com/')])
-        self.assertErrorPage(403, 'Forbidden Referer header.')
-
-
-class AcceptTest(helper.CPWebCase):
-    
-    def test_Accept_Tool(self):
-        # Test with no header provided
-        self.getPage('/accept/feed')
-        self.assertStatus(200)
-        self.assertInBody('<title>Unknown Blog</title>')
-        
-        # Specify exact media type
-        self.getPage('/accept/feed', headers=[('Accept', 'application/atom+xml')])
-        self.assertStatus(200)
-        self.assertInBody('<title>Unknown Blog</title>')
-        
-        # Specify matching media range
-        self.getPage('/accept/feed', headers=[('Accept', 'application/*')])
-        self.assertStatus(200)
-        self.assertInBody('<title>Unknown Blog</title>')
-        
-        # Specify all media ranges
-        self.getPage('/accept/feed', headers=[('Accept', '*/*')])
-        self.assertStatus(200)
-        self.assertInBody('<title>Unknown Blog</title>')
-        
-        # Specify unacceptable media types
-        self.getPage('/accept/feed', headers=[('Accept', 'text/html')])
-        self.assertErrorPage(406,
-                             "Your client sent this Accept header: text/html. "
-                             "But this resource only emits these media types: "
-                             "application/atom+xml.")
-        
-        # Test resource where tool is 'on' but media is None (not set).
-        self.getPage('/accept/')
-        self.assertStatus(200)
-        self.assertBody('<a href="feed">Atom feed</a>')
-    
-    def test_accept_selection(self):
-        # Try both our expected media types
-        self.getPage('/accept/select', [('Accept', 'text/html')])
-        self.assertStatus(200)
-        self.assertBody('<h2>Page Title</h2>')
-        self.getPage('/accept/select', [('Accept', 'text/plain')])
-        self.assertStatus(200)
-        self.assertBody('PAGE TITLE')
-        self.getPage('/accept/select', [('Accept', 'text/plain, text/*;q=0.5')])
-        self.assertStatus(200)
-        self.assertBody('PAGE TITLE')
-        
-        # text/* and */* should prefer text/html since it comes first
-        # in our 'media' argument to tools.accept
-        self.getPage('/accept/select', [('Accept', 'text/*')])
-        self.assertStatus(200)
-        self.assertBody('<h2>Page Title</h2>')
-        self.getPage('/accept/select', [('Accept', '*/*')])
-        self.assertStatus(200)
-        self.assertBody('<h2>Page Title</h2>')
-        
-        # Try unacceptable media types
-        self.getPage('/accept/select', [('Accept', 'application/xml')])
-        self.assertErrorPage(406,
-                             "Your client sent this Accept header: application/xml. "
-                             "But this resource only emits these media types: "
-                             "text/html, text/plain.")
-
-
-class AutoVaryTest(helper.CPWebCase):
-
-    def testAutoVary(self):
-        self.getPage('/autovary/')
-        self.assertHeader(
-            "Vary", 'Accept, Accept-Charset, Accept-Encoding, Host, If-Modified-Since, Range')
-
-
-if __name__ == "__main__":
-    helper.testmain()
--- a/bundled/cherrypy/cherrypy/test/test_objectmapping.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,394 +0,0 @@
-from cherrypy.test import test
-from cherrypy._cptree import Application
-test.prefer_parent_path()
-
-import cherrypy
-
-
-script_names = ["", "/foo", "/users/fred/blog", "/corp/blog"]
-
-def setup_server():
-    class Root:
-        def index(self, name="world"):
-            return name
-        index.exposed = True
-        
-        def foobar(self):
-            return "bar"
-        foobar.exposed = True
-        
-        def default(self, *params, **kwargs):
-            return "default:" + repr(params)
-        default.exposed = True
-        
-        def other(self):
-            return "other"
-        other.exposed = True
-        
-        def extra(self, *p):
-            return repr(p)
-        extra.exposed = True
-        
-        def redirect(self):
-            raise cherrypy.HTTPRedirect('dir1/', 302)
-        redirect.exposed = True
-        
-        def notExposed(self):
-            return "not exposed"
-        
-        def confvalue(self):
-            return cherrypy.request.config.get("user")
-        confvalue.exposed = True
-        
-        def redirect_via_url(self, path):
-            raise cherrypy.HTTPRedirect(cherrypy.url(path))
-        redirect_via_url.exposed = True
-    
-    def mapped_func(self, ID=None):
-        return "ID is %s" % ID
-    mapped_func.exposed = True
-    setattr(Root, "Von B\xfclow", mapped_func)
-    
-    
-    class Exposing:
-        def base(self):
-            return "expose works!"
-        cherrypy.expose(base)
-        cherrypy.expose(base, "1")
-        cherrypy.expose(base, "2")
-    
-    class ExposingNewStyle(object):
-        def base(self):
-            return "expose works!"
-        cherrypy.expose(base)
-        cherrypy.expose(base, "1")
-        cherrypy.expose(base, "2")
-    
-    
-    class Dir1:
-        def index(self):
-            return "index for dir1"
-        index.exposed = True
-        
-        def myMethod(self):
-            return "myMethod from dir1, path_info is:" + repr(cherrypy.request.path_info)
-        myMethod.exposed = True
-        myMethod._cp_config = {'tools.trailing_slash.extra': True}
-        
-        def default(self, *params):
-            return "default for dir1, param is:" + repr(params)
-        default.exposed = True
-
-
-    class Dir2:
-        def index(self):
-            return "index for dir2, path is:" + cherrypy.request.path_info
-        index.exposed = True
-        
-        def script_name(self):
-            return cherrypy.tree.script_name()
-        script_name.exposed = True
-        
-        def cherrypy_url(self):
-            return cherrypy.url("/extra")
-        cherrypy_url.exposed = True
-        
-        def posparam(self, *vpath):
-            return "/".join(vpath)
-        posparam.exposed = True
-    
-    
-    class Dir3:
-        def default(self):
-            return "default for dir3, not exposed"
-    
-    class Dir4:
-        def index(self):
-            return "index for dir4, not exposed"
-    
-    class DefNoIndex:
-        def default(self, *args):
-            raise cherrypy.HTTPRedirect("contact")
-        default.exposed = True
-    
-    # MethodDispatcher code
-    class ByMethod:
-        exposed = True
-        
-        def __init__(self, *things):
-            self.things = list(things)
-        
-        def GET(self):
-            return repr(self.things)
-        
-        def POST(self, thing):
-            self.things.append(thing)
-    
-    class Collection:
-        default = ByMethod('a', 'bit')
-    
-    Root.exposing = Exposing()
-    Root.exposingnew = ExposingNewStyle()
-    Root.dir1 = Dir1()
-    Root.dir1.dir2 = Dir2()
-    Root.dir1.dir2.dir3 = Dir3()
-    Root.dir1.dir2.dir3.dir4 = Dir4()
-    Root.defnoindex = DefNoIndex()
-    Root.bymethod = ByMethod('another')
-    Root.collection = Collection()
-    
-    d = cherrypy.dispatch.MethodDispatcher()
-    for url in script_names:
-        conf = {'/': {'user': (url or "/").split("/")[-2]},
-                '/bymethod': {'request.dispatch': d},
-                '/collection': {'request.dispatch': d},
-                }
-        cherrypy.tree.mount(Root(), url, conf)
-    
-    
-    class Isolated:
-        def index(self):
-            return "made it!"
-        index.exposed = True
-    
-    cherrypy.tree.mount(Isolated(), "/isolated")
-    
-    class AnotherApp:
-        
-        exposed = True
-        
-        def GET(self):
-            return "milk"
-    
-    cherrypy.tree.mount(AnotherApp(), "/app", {'/': {'request.dispatch': d}})
-
-
-from cherrypy.test import helper
-
-class ObjectMappingTest(helper.CPWebCase):
-    
-    def testObjectMapping(self):
-        for url in script_names:
-            prefix = self.script_name = url
-            
-            self.getPage('/')
-            self.assertBody('world')
-            
-            self.getPage("/dir1/myMethod")
-            self.assertBody("myMethod from dir1, path_info is:'/dir1/myMethod'")
-            
-            self.getPage("/this/method/does/not/exist")
-            self.assertBody("default:('this', 'method', 'does', 'not', 'exist')")
-            
-            self.getPage("/extra/too/much")
-            self.assertBody("('too', 'much')")
-            
-            self.getPage("/other")
-            self.assertBody('other')
-            
-            self.getPage("/notExposed")
-            self.assertBody("default:('notExposed',)")
-            
-            self.getPage("/dir1/dir2/")
-            self.assertBody('index for dir2, path is:/dir1/dir2/')
-            
-            # Test omitted trailing slash (should be redirected by default).
-            self.getPage("/dir1/dir2")
-            self.assertStatus(301)
-            self.assertHeader('Location', '%s/dir1/dir2/' % self.base())
-            
-            # Test extra trailing slash (should be redirected if configured).
-            self.getPage("/dir1/myMethod/")
-            self.assertStatus(301)
-            self.assertHeader('Location', '%s/dir1/myMethod' % self.base())
-            
-            # Test that default method must be exposed in order to match.
-            self.getPage("/dir1/dir2/dir3/dir4/index")
-            self.assertBody("default for dir1, param is:('dir2', 'dir3', 'dir4', 'index')")
-            
-            # Test *vpath when default() is defined but not index()
-            # This also tests HTTPRedirect with default.
-            self.getPage("/defnoindex")
-            self.assertStatus((302, 303))
-            self.assertHeader('Location', '%s/contact' % self.base())
-            self.getPage("/defnoindex/")
-            self.assertStatus((302, 303))
-            self.assertHeader('Location', '%s/defnoindex/contact' % self.base())
-            self.getPage("/defnoindex/page")
-            self.assertStatus((302, 303))
-            self.assertHeader('Location', '%s/defnoindex/contact' % self.base())
-            
-            self.getPage("/redirect")
-            self.assertStatus('302 Found')
-            self.assertHeader('Location', '%s/dir1/' % self.base())
-            
-            if not getattr(cherrypy.server, "using_apache", False):
-                # Test that we can use URL's which aren't all valid Python identifiers
-                # This should also test the %XX-unquoting of URL's.
-                self.getPage("/Von%20B%fclow?ID=14")
-                self.assertBody("ID is 14")
-                
-                # Test that %2F in the path doesn't get unquoted too early;
-                # that is, it should not be used to separate path components.
-                # See ticket #393.
-                self.getPage("/page%2Fname")
-                self.assertBody("default:('page/name',)")
-            
-            self.getPage("/dir1/dir2/script_name")
-            self.assertBody(url)
-            self.getPage("/dir1/dir2/cherrypy_url")
-            self.assertBody("%s/extra" % self.base())
-            
-            # Test that configs don't overwrite each other from diferent apps
-            self.getPage("/confvalue")
-            self.assertBody((url or "/").split("/")[-2])
-        
-        self.script_name = ""
-        
-        # Test absoluteURI's in the Request-Line
-        self.getPage('http://%s:%s/' % (self.interface(), self.PORT))
-        self.assertBody('world')
-        
-        self.getPage('http://%s:%s/abs/?service=http://192.168.0.1/x/y/z' %
-                     (self.interface(), self.PORT))
-        self.assertBody("default:('abs',)")
-        
-        self.getPage('/rel/?service=http://192.168.120.121:8000/x/y/z')
-        self.assertBody("default:('rel',)")
-        
-        # Test that the "isolated" app doesn't leak url's into the root app.
-        # If it did leak, Root.default() would answer with
-        #   "default:('isolated', 'doesnt', 'exist')".
-        self.getPage("/isolated/")
-        self.assertStatus("200 OK")
-        self.assertBody("made it!")
-        self.getPage("/isolated/doesnt/exist")
-        self.assertStatus("404 Not Found")
-        
-        # Make sure /foobar maps to Root.foobar and not to the app
-        # mounted at /foo. See http://www.cherrypy.org/ticket/573
-        self.getPage("/foobar")
-        self.assertBody("bar")
-    
-    def test_redir_using_url(self):
-        for url in script_names:
-            prefix = self.script_name = url
-            
-            # Test the absolute path to the parent (leading slash)
-            self.getPage('/redirect_via_url?path=./')
-            self.assertStatus(('302 Found', '303 See Other'))
-            self.assertHeader('Location', '%s/' % self.base())
-            
-            # Test the relative path to the parent (no leading slash)
-            self.getPage('/redirect_via_url?path=./')
-            self.assertStatus(('302 Found', '303 See Other'))
-            self.assertHeader('Location', '%s/' % self.base())
-            
-            # Test the absolute path to the parent (leading slash)
-            self.getPage('/redirect_via_url/?path=./')
-            self.assertStatus(('302 Found', '303 See Other'))
-            self.assertHeader('Location', '%s/' % self.base())
-            
-            # Test the relative path to the parent (no leading slash)
-            self.getPage('/redirect_via_url/?path=./')
-            self.assertStatus(('302 Found', '303 See Other'))
-            self.assertHeader('Location', '%s/' % self.base())
-    
-    def testPositionalParams(self):
-        self.getPage("/dir1/dir2/posparam/18/24/hut/hike")
-        self.assertBody("18/24/hut/hike")
-        
-        # intermediate index methods should not receive posparams;
-        # only the "final" index method should do so.
-        self.getPage("/dir1/dir2/5/3/sir")
-        self.assertBody("default for dir1, param is:('dir2', '5', '3', 'sir')")
-        
-        # test that extra positional args raises an 404 Not Found
-        # See http://www.cherrypy.org/ticket/733.
-        self.getPage("/dir1/dir2/script_name/extra/stuff")
-        self.assertStatus(404)
-    
-    def testExpose(self):
-        # Test the cherrypy.expose function/decorator
-        self.getPage("/exposing/base")
-        self.assertBody("expose works!")
-        
-        self.getPage("/exposing/1")
-        self.assertBody("expose works!")
-        
-        self.getPage("/exposing/2")
-        self.assertBody("expose works!")
-        
-        self.getPage("/exposingnew/base")
-        self.assertBody("expose works!")
-        
-        self.getPage("/exposingnew/1")
-        self.assertBody("expose works!")
-        
-        self.getPage("/exposingnew/2")
-        self.assertBody("expose works!")
-    
-    def testMethodDispatch(self):
-        self.getPage("/bymethod")
-        self.assertBody("['another']")
-        self.assertHeader('Allow', 'GET, HEAD, POST')
-        
-        self.getPage("/bymethod", method="HEAD")
-        self.assertBody("")
-        self.assertHeader('Allow', 'GET, HEAD, POST')
-        
-        self.getPage("/bymethod", method="POST", body="thing=one")
-        self.assertBody("")
-        self.assertHeader('Allow', 'GET, HEAD, POST')
-        
-        self.getPage("/bymethod")
-        self.assertBody("['another', u'one']")
-        self.assertHeader('Allow', 'GET, HEAD, POST')
-        
-        self.getPage("/bymethod", method="PUT")
-        self.assertErrorPage(405)
-        self.assertHeader('Allow', 'GET, HEAD, POST')
-        
-        # Test default with posparams
-        self.getPage("/collection/silly", method="POST")
-        self.getPage("/collection", method="GET")
-        self.assertBody("['a', 'bit', 'silly']")
-        
-        # Test custom dispatcher set on app root (see #737).
-        self.getPage("/app")
-        self.assertBody("milk")
-
-    def testTreeMounting(self):
-        class Root(object):
-            def hello(self):
-                return "Hello world!"
-            hello.exposed = True
-        
-        # When mounting an application instance, 
-        # we can't specify a different script name in the call to mount.
-        a = Application(Root(), '/somewhere')
-        self.assertRaises(ValueError, cherrypy.tree.mount, a, '/somewhereelse')
-        
-        # When mounting an application instance...
-        a = Application(Root(), '/somewhere')
-        # ...we MUST allow in identical script name in the call to mount...
-        cherrypy.tree.mount(a, '/somewhere')
-        self.getPage('/somewhere/hello')
-        self.assertStatus(200)
-        # ...and MUST allow a missing script_name.
-        del cherrypy.tree.apps['/somewhere']
-        cherrypy.tree.mount(a)
-        self.getPage('/somewhere/hello')
-        self.assertStatus(200)
-        
-        # In addition, we MUST be able to create an Application using
-        # script_name == None for access to the wsgi_environ.
-        a = Application(Root(), script_name=None)
-        # However, this does not apply to tree.mount
-        self.assertRaises(TypeError, cherrypy.tree.mount, a, None)
-
-
-
-
-if __name__ == "__main__":
-    helper.testmain()
--- a/bundled/cherrypy/cherrypy/test/test_proxy.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,135 +0,0 @@
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import cherrypy
-
-script_names = ["", "/path/to/myapp"]
-
-def setup_server():
-    
-    # Set up site
-    cherrypy.config.update({
-        'tools.proxy.on': True,
-        'tools.proxy.base': 'www.mydomain.test',
-        })
-    
-    # Set up application
-    
-    class Root:
-        
-        def __init__(self, sn):
-            # Calculate a URL outside of any requests.
-            self.thisnewpage = cherrypy.url("/this/new/page", script_name=sn)
-        
-        def pageurl(self):
-            return self.thisnewpage
-        pageurl.exposed = True
-        
-        def index(self):
-            raise cherrypy.HTTPRedirect('dummy')
-        index.exposed = True
-        
-        def remoteip(self):
-            return cherrypy.request.remote.ip
-        remoteip.exposed = True
-        
-        def xhost(self):
-            raise cherrypy.HTTPRedirect('blah')
-        xhost.exposed = True
-        xhost._cp_config = {'tools.proxy.local': 'X-Host',
-                            'tools.trailing_slash.extra': True,
-                            }
-        
-        def base(self):
-            return cherrypy.request.base
-        base.exposed = True
-        
-        def ssl(self):
-            return cherrypy.request.base
-        ssl.exposed = True
-        ssl._cp_config = {'tools.proxy.scheme': 'X-Forwarded-Ssl'}
-        
-        def newurl(self):
-            return ("Browse to <a href='%s'>this page</a>."
-                    % cherrypy.url("/this/new/page"))
-        newurl.exposed = True
-    
-    for sn in script_names:
-        cherrypy.tree.mount(Root(sn), sn)
-
-
-from cherrypy.test import helper
-
-class ProxyTest(helper.CPWebCase):
-    
-    def testProxy(self):
-        self.getPage("/")
-        self.assertHeader('Location',
-                          "%s://www.mydomain.test%s/dummy" %
-                          (self.scheme, self.prefix()))
-        
-        # Test X-Forwarded-Host (Apache 1.3.33+ and Apache 2)
-        self.getPage("/", headers=[('X-Forwarded-Host', 'http://www.example.test')])
-        self.assertHeader('Location', "http://www.example.test/dummy")
-        self.getPage("/", headers=[('X-Forwarded-Host', 'www.example.test')])
-        self.assertHeader('Location', "%s://www.example.test/dummy" % self.scheme)
-        # Test multiple X-Forwarded-Host headers
-        self.getPage("/", headers=[
-            ('X-Forwarded-Host', 'http://www.example.test, www.cherrypy.test'),
-            ])
-        self.assertHeader('Location', "http://www.example.test/dummy")
-        
-        # Test X-Forwarded-For (Apache2)
-        self.getPage("/remoteip",
-                     headers=[('X-Forwarded-For', '192.168.0.20')])
-        self.assertBody("192.168.0.20")
-        self.getPage("/remoteip",
-                     headers=[('X-Forwarded-For', '67.15.36.43, 192.168.0.20')])
-        self.assertBody("192.168.0.20")
-        
-        # Test X-Host (lighttpd; see https://trac.lighttpd.net/trac/ticket/418)
-        self.getPage("/xhost", headers=[('X-Host', 'www.example.test')])
-        self.assertHeader('Location', "%s://www.example.test/blah" % self.scheme)
-        
-        # Test X-Forwarded-Proto (lighttpd)
-        self.getPage("/base", headers=[('X-Forwarded-Proto', 'https')])
-        self.assertBody("https://www.mydomain.test")
-        
-        # Test X-Forwarded-Ssl (webfaction?)
-        self.getPage("/ssl", headers=[('X-Forwarded-Ssl', 'on')])
-        self.assertBody("https://www.mydomain.test")
-        
-        # Test cherrypy.url()
-        for sn in script_names:
-            # Test the value inside requests
-            self.getPage(sn + "/newurl")
-            self.assertBody("Browse to <a href='%s://www.mydomain.test" % self.scheme
-                            + sn + "/this/new/page'>this page</a>.")
-            self.getPage(sn + "/newurl", headers=[('X-Forwarded-Host',
-                                                   'http://www.example.test')])
-            self.assertBody("Browse to <a href='http://www.example.test"
-                            + sn + "/this/new/page'>this page</a>.")
-            
-            # Test the value outside requests
-            port = ""
-            if self.scheme == "http" and self.PORT != 80:
-                port = ":%s" % self.PORT
-            elif self.scheme == "https" and self.PORT != 443:
-                port = ":%s" % self.PORT
-            host = self.HOST
-            if host in ('0.0.0.0', '::'):
-                import socket
-                host = socket.gethostname()
-            expected = ("%s://%s%s%s/this/new/page"
-                        % (self.scheme, host, port, sn))
-            self.getPage(sn + "/pageurl")
-            self.assertBody(expected)
-        
-        # Test trailing slash (see http://www.cherrypy.org/ticket/562).
-        self.getPage("/xhost/", headers=[('X-Host', 'www.example.test')])
-        self.assertHeader('Location', "%s://www.example.test/xhost"
-                          % self.scheme)
-
-
-if __name__ == '__main__':
-    helper.testmain()
--- a/bundled/cherrypy/cherrypy/test/test_refleaks.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +0,0 @@
-"""Tests for refleaks."""
-
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import gc
-from httplib import HTTPConnection, HTTPSConnection
-import threading
-
-import cherrypy
-from cherrypy import _cprequest
-
-
-data = object()
-
-def get_instances(cls):
-    return [x for x in gc.get_objects() if isinstance(x, cls)]
-
-def setup_server():
-    
-    class Root:
-        def index(self, *args, **kwargs):
-            cherrypy.request.thing = data
-            return "Hello world!"
-        index.exposed = True
-        
-        def gc_stats(self):
-            output = ["Statistics:"]
-            
-            # Uncollectable garbage
-            
-            # gc_collect isn't perfectly synchronous, because it may
-            # break reference cycles that then take time to fully
-            # finalize. Call it twice and hope for the best.
-            gc.collect()
-            unreachable = gc.collect()
-            if unreachable:
-                output.append("\n%s unreachable objects:" % unreachable)
-                trash = {}
-                for x in gc.garbage:
-                    trash[type(x)] = trash.get(type(x), 0) + 1
-                trash = [(v, k) for k, v in trash.iteritems()]
-                trash.sort()
-                for pair in trash:
-                    output.append("    " + repr(pair))
-            
-            # Request references
-            reqs = get_instances(_cprequest.Request)
-            lenreqs = len(reqs)
-            if lenreqs < 2:
-                output.append("\nMissing Request reference. Should be 1 in "
-                              "this request thread and 1 in the main thread.")
-            elif lenreqs > 2:
-                output.append("\nToo many Request references (%r)." % lenreqs)
-                for req in reqs:
-                    output.append("Referrers for %s:" % repr(req))
-                    for ref in gc.get_referrers(req):
-                        if ref is not reqs:
-                            output.append("    %s" % repr(ref))
-            
-            # Response references
-            resps = get_instances(_cprequest.Response)
-            lenresps = len(resps)
-            if lenresps < 2:
-                output.append("\nMissing Response reference. Should be 1 in "
-                              "this request thread and 1 in the main thread.")
-            elif lenresps > 2:
-                output.append("\nToo many Response references (%r)." % lenresps)
-                for resp in resps:
-                    output.append("Referrers for %s:" % repr(resp))
-                    for ref in gc.get_referrers(resp):
-                        if ref is not resps:
-                            output.append("    %s" % repr(ref))
-            
-            return "\n".join(output)
-        gc_stats.exposed = True
-    
-    cherrypy.tree.mount(Root())
-
-
-from cherrypy.test import helper
-
-
-class ReferenceTests(helper.CPWebCase):
-    
-    def test_threadlocal_garbage(self):
-        success = []
-        
-        def getpage():
-            host = '%s:%s' % (self.interface(), self.PORT)
-            if self.scheme == 'https':
-                c = HTTPSConnection(host)
-            else:
-                c = HTTPConnection(host)
-            try:
-                c.putrequest('GET', '/')
-                c.endheaders()
-                response = c.getresponse()
-                body = response.read()
-                self.assertEqual(response.status, 200)
-                self.assertEqual(body, "Hello world!")
-            finally:
-                c.close()
-            success.append(True)
-        
-        ITERATIONS = 25
-        ts = []
-        for _ in range(ITERATIONS):
-            t = threading.Thread(target=getpage)
-            ts.append(t)
-            t.start()
-        
-        for t in ts:
-            t.join()
-        
-        self.assertEqual(len(success), ITERATIONS)
-        
-        self.getPage("/gc_stats")
-        self.assertBody("Statistics:")
-
-
-if __name__ == '__main__':
-    helper.testmain({'server.socket_queue_size': 10})
--- a/bundled/cherrypy/cherrypy/test/test_request_obj.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,728 +0,0 @@
-"""Basic tests for the cherrypy.Request object."""
-
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import os
-localDir = os.path.dirname(__file__)
-import sys
-import types
-from httplib import IncompleteRead
-
-import cherrypy
-from cherrypy import _cptools, tools
-from cherrypy.lib import static, httputil
-
-defined_http_methods = ("OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE",
-                        "TRACE", "PROPFIND")
-
-
-def setup_server():
-    class Root:
-        
-        def index(self):
-            return "hello"
-        index.exposed = True
-        
-        def scheme(self):
-            return cherrypy.request.scheme
-        scheme.exposed = True
-    
-    root = Root()
-    
-    
-    class TestType(type):
-        """Metaclass which automatically exposes all functions in each subclass,
-        and adds an instance of the subclass as an attribute of root.
-        """
-        def __init__(cls, name, bases, dct):
-            type.__init__(cls, name, bases, dct)
-            for value in dct.itervalues():
-                if isinstance(value, types.FunctionType):
-                    value.exposed = True
-            setattr(root, name.lower(), cls())
-    class Test(object):
-        __metaclass__ = TestType
-    
-    
-    class Params(Test):
-        
-        def index(self, thing):
-            return repr(thing)
-        
-        def ismap(self, x, y):
-            return "Coordinates: %s, %s" % (x, y)
-        
-        def default(self, *args, **kwargs):
-            return "args: %s kwargs: %s" % (args, kwargs)
-        default._cp_config = {'request.query_string_encoding': 'latin1'}
-
-
-    class ParamErrorsCallable(object):
-        exposed = True
-        def __call__(self):
-            return "data"
-
-    class ParamErrors(Test):
-
-        def one_positional(self, param1):
-            return "data"
-        one_positional.exposed = True
-
-        def one_positional_args(self, param1, *args):
-            return "data"
-        one_positional_args.exposed = True
-
-        def one_positional_args_kwargs(self, param1, *args, **kwargs):
-            return "data"
-        one_positional_args_kwargs.exposed = True
-
-        def one_positional_kwargs(self, param1, **kwargs):
-            return "data"
-        one_positional_kwargs.exposed = True
-
-        def no_positional(self):
-            return "data"
-        no_positional.exposed = True
-
-        def no_positional_args(self, *args):
-            return "data"
-        no_positional_args.exposed = True
-
-        def no_positional_args_kwargs(self, *args, **kwargs):
-            return "data"
-        no_positional_args_kwargs.exposed = True
-
-        def no_positional_kwargs(self, **kwargs):
-            return "data"
-        no_positional_kwargs.exposed = True
-
-        callable_object = ParamErrorsCallable()
-
-        def raise_type_error(self, **kwargs):
-            raise TypeError("Client Error")
-        raise_type_error.exposed = True
-
-        def raise_type_error_with_default_param(self, x, y=None):
-            return '%d' % 'a' # throw an exception
-        raise_type_error_with_default_param.exposed = True
-
-    def callable_error_page(status, **kwargs):
-        return "Error %s - Well, I'm very sorry but you haven't paid!" % status
-    
-    
-    class Error(Test):
-        
-        _cp_config = {'tools.log_tracebacks.on': True,
-                      }
-        
-        def reason_phrase(self):
-            raise cherrypy.HTTPError("410 Gone fishin'")
-        
-        def custom(self, err='404'):
-            raise cherrypy.HTTPError(int(err), "No, <b>really</b>, not found!")
-        custom._cp_config = {'error_page.404': os.path.join(localDir, "static/index.html"),
-                             'error_page.401': callable_error_page,
-                             }
-        
-        def custom_default(self):
-            return 1 + 'a' # raise an unexpected error
-        custom_default._cp_config = {'error_page.default': callable_error_page}
-        
-        def noexist(self):
-            raise cherrypy.HTTPError(404, "No, <b>really</b>, not found!")
-        noexist._cp_config = {'error_page.404': "nonexistent.html"}
-        
-        def page_method(self):
-            raise ValueError()
-        
-        def page_yield(self):
-            yield "howdy"
-            raise ValueError()
-        
-        def page_streamed(self):
-            yield "word up"
-            raise ValueError()
-            yield "very oops"
-        page_streamed._cp_config = {"response.stream": True}
-        
-        def cause_err_in_finalize(self):
-            # Since status must start with an int, this should error.
-            cherrypy.response.status = "ZOO OK"
-        cause_err_in_finalize._cp_config = {'request.show_tracebacks': False}
-        
-        def rethrow(self):
-            """Test that an error raised here will be thrown out to the server."""
-            raise ValueError()
-        rethrow._cp_config = {'request.throw_errors': True}
-    
-    
-    class Expect(Test):
-        
-        def expectation_failed(self):
-            expect = cherrypy.request.headers.elements("Expect")
-            if expect and expect[0].value != '100-continue':
-                raise cherrypy.HTTPError(400)
-            raise cherrypy.HTTPError(417, 'Expectation Failed')
-
-    class Headers(Test):
-        
-        def default(self, headername):
-            """Spit back out the value for the requested header."""
-            return cherrypy.request.headers[headername]
-        
-        def doubledheaders(self):
-            # From http://www.cherrypy.org/ticket/165:
-            # "header field names should not be case sensitive sayes the rfc.
-            # if i set a headerfield in complete lowercase i end up with two
-            # header fields, one in lowercase, the other in mixed-case."
-            
-            # Set the most common headers
-            hMap = cherrypy.response.headers
-            hMap['content-type'] = "text/html"
-            hMap['content-length'] = 18
-            hMap['server'] = 'CherryPy headertest'
-            hMap['location'] = ('%s://%s:%s/headers/'
-                                % (cherrypy.request.local.ip,
-                                   cherrypy.request.local.port,
-                                   cherrypy.request.scheme))
-            
-            # Set a rare header for fun
-            hMap['Expires'] = 'Thu, 01 Dec 2194 16:00:00 GMT'
-            
-            return "double header test"
-        
-        def ifmatch(self):
-            val = cherrypy.request.headers['If-Match']
-            assert isinstance(val, unicode)
-            cherrypy.response.headers['ETag'] = val
-            return val
-    
-    
-    class HeaderElements(Test):
-        
-        def get_elements(self, headername):
-            e = cherrypy.request.headers.elements(headername)
-            return "\n".join([unicode(x) for x in e])
-    
-    
-    class Method(Test):
-        
-        def index(self):
-            m = cherrypy.request.method
-            if m in defined_http_methods or m == "CONNECT":
-                return m
-            
-            if m == "LINK":
-                raise cherrypy.HTTPError(405)
-            else:
-                raise cherrypy.HTTPError(501)
-        
-        def parameterized(self, data):
-            return data
-        
-        def request_body(self):
-            # This should be a file object (temp file),
-            # which CP will just pipe back out if we tell it to.
-            return cherrypy.request.body
-        
-        def reachable(self):
-            return "success"
-
-    class Divorce:
-        """HTTP Method handlers shouldn't collide with normal method names.
-        For example, a GET-handler shouldn't collide with a method named 'get'.
-        
-        If you build HTTP method dispatching into CherryPy, rewrite this class
-        to use your new dispatch mechanism and make sure that:
-            "GET /divorce HTTP/1.1" maps to divorce.index() and
-            "GET /divorce/get?ID=13 HTTP/1.1" maps to divorce.get()
-        """
-        
-        documents = {}
-        
-        def index(self):
-            yield "<h1>Choose your document</h1>\n"
-            yield "<ul>\n"
-            for id, contents in self.documents.items():
-                yield ("    <li><a href='/divorce/get?ID=%s'>%s</a>: %s</li>\n"
-                       % (id, id, contents))
-            yield "</ul>"
-        index.exposed = True
-        
-        def get(self, ID):
-            return ("Divorce document %s: %s" %
-                    (ID, self.documents.get(ID, "empty")))
-        get.exposed = True
-
-    root.divorce = Divorce()
-
-
-    class ThreadLocal(Test):
-        
-        def index(self):
-            existing = repr(getattr(cherrypy.request, "asdf", None))
-            cherrypy.request.asdf = "rassfrassin"
-            return existing
-    
-    appconf = {
-        '/method': {'request.methods_with_bodies': ("POST", "PUT", "PROPFIND")},
-        }
-    cherrypy.tree.mount(root, config=appconf)
-
-
-#                             Client-side code                             #
-
-from cherrypy.test import helper
-
-class RequestObjectTests(helper.CPWebCase):
-    
-    def test_scheme(self):
-        self.getPage("/scheme")
-        self.assertBody(self.scheme)
-    
-    def testParams(self):
-        self.getPage("/params/?thing=a")
-        self.assertBody("u'a'")
-        
-        self.getPage("/params/?thing=a&thing=b&thing=c")
-        self.assertBody("[u'a', u'b', u'c']")
-
-        # Test friendly error message when given params are not accepted.
-        cherrypy.config.update({"request.show_mismatched_params": True})
-        self.getPage("/params/?notathing=meeting")
-        self.assertInBody("Missing parameters: thing")
-        self.getPage("/params/?thing=meeting&notathing=meeting")
-        self.assertInBody("Unexpected query string parameters: notathing")
-        
-        # Test ability to turn off friendly error messages
-        cherrypy.config.update({"request.show_mismatched_params": False})
-        self.getPage("/params/?notathing=meeting")
-        self.assertInBody("Not Found")
-        self.getPage("/params/?thing=meeting&notathing=meeting")
-        self.assertInBody("Not Found")
-
-        # Test "% HEX HEX"-encoded URL, param keys, and values
-        self.getPage("/params/%d4%20%e3/cheese?Gruy%E8re=Bulgn%e9ville")
-        self.assertBody(r"args: ('\xd4 \xe3', 'cheese') "
-                        r"kwargs: {'Gruy\xe8re': u'Bulgn\xe9ville'}")
-        
-        # Make sure that encoded = and & get parsed correctly
-        self.getPage("/params/code?url=http%3A//cherrypy.org/index%3Fa%3D1%26b%3D2")
-        self.assertBody(r"args: ('code',) "
-                        r"kwargs: {'url': u'http://cherrypy.org/index?a=1&b=2'}")
-        
-        # Test coordinates sent by <img ismap>
-        self.getPage("/params/ismap?223,114")
-        self.assertBody("Coordinates: 223, 114")
-        
-        # Test "name[key]" dict-like params
-        self.getPage("/params/dictlike?a[1]=1&a[2]=2&b=foo&b[bar]=baz")
-        self.assertBody(
-            "args: ('dictlike',) "
-            "kwargs: {'a[1]': u'1', 'b[bar]': u'baz', 'b': u'foo', 'a[2]': u'2'}")
-
-    def testParamErrors(self):
-
-        # test that all of the handlers work when given 
-        # the correct parameters in order to ensure that the
-        # errors below aren't coming from some other source.
-        for uri in (
-                '/paramerrors/one_positional?param1=foo',
-                '/paramerrors/one_positional_args?param1=foo',
-                '/paramerrors/one_positional_args/foo',
-                '/paramerrors/one_positional_args/foo/bar/baz',
-                '/paramerrors/one_positional_args_kwargs?param1=foo&param2=bar',
-                '/paramerrors/one_positional_args_kwargs/foo?param2=bar&param3=baz',
-                '/paramerrors/one_positional_args_kwargs/foo/bar/baz?param2=bar&param3=baz',
-                '/paramerrors/one_positional_kwargs?param1=foo&param2=bar&param3=baz',
-                '/paramerrors/one_positional_kwargs/foo?param4=foo&param2=bar&param3=baz',
-                '/paramerrors/no_positional',
-                '/paramerrors/no_positional_args/foo',
-                '/paramerrors/no_positional_args/foo/bar/baz',
-                '/paramerrors/no_positional_args_kwargs?param1=foo&param2=bar',
-                '/paramerrors/no_positional_args_kwargs/foo?param2=bar',
-                '/paramerrors/no_positional_args_kwargs/foo/bar/baz?param2=bar&param3=baz',
-                '/paramerrors/no_positional_kwargs?param1=foo&param2=bar',
-                '/paramerrors/callable_object',
-            ):
-            self.getPage(uri)
-            self.assertStatus(200)
-
-        # query string parameters are part of the URI, so if they are wrong
-        # for a particular handler, the status MUST be a 404.
-        error_msgs = [
-                'Missing parameters',
-                'Nothing matches the given URI',
-                'Multiple values for parameters',
-                'Unexpected query string parameters',
-                'Unexpected body parameters',
-            ]
-        for uri, msg in (
-            ('/paramerrors/one_positional', error_msgs[0]),
-            ('/paramerrors/one_positional?foo=foo', error_msgs[0]),
-            ('/paramerrors/one_positional/foo/bar/baz', error_msgs[1]),
-            ('/paramerrors/one_positional/foo?param1=foo', error_msgs[2]),
-            ('/paramerrors/one_positional/foo?param1=foo&param2=foo', error_msgs[2]),
-            ('/paramerrors/one_positional_args/foo?param1=foo&param2=foo', error_msgs[2]),
-            ('/paramerrors/one_positional_args/foo/bar/baz?param2=foo', error_msgs[3]),
-            ('/paramerrors/one_positional_args_kwargs/foo/bar/baz?param1=bar&param3=baz', error_msgs[2]),
-            ('/paramerrors/one_positional_kwargs/foo?param1=foo&param2=bar&param3=baz', error_msgs[2]),
-            ('/paramerrors/no_positional/boo', error_msgs[1]),
-            ('/paramerrors/no_positional?param1=foo', error_msgs[3]),
-            ('/paramerrors/no_positional_args/boo?param1=foo', error_msgs[3]),
-            ('/paramerrors/no_positional_kwargs/boo?param1=foo', error_msgs[1]),
-            ('/paramerrors/callable_object?param1=foo', error_msgs[3]),
-            ('/paramerrors/callable_object/boo', error_msgs[1]),
-            ):
-            for show_mismatched_params in (True, False):
-                cherrypy.config.update({'request.show_mismatched_params': show_mismatched_params})
-                self.getPage(uri)
-                self.assertStatus(404)
-                if show_mismatched_params:
-                    self.assertInBody(msg)
-                else:
-                    self.assertInBody("Not Found")
-
-        # if body parameters are wrong, a 400 must be returned.
-        for uri, body, msg in (
-                ('/paramerrors/one_positional/foo', 'param1=foo', error_msgs[2]),
-                ('/paramerrors/one_positional/foo', 'param1=foo&param2=foo', error_msgs[2]),
-                ('/paramerrors/one_positional_args/foo', 'param1=foo&param2=foo', error_msgs[2]),
-                ('/paramerrors/one_positional_args/foo/bar/baz', 'param2=foo', error_msgs[4]),
-                ('/paramerrors/one_positional_args_kwargs/foo/bar/baz', 'param1=bar&param3=baz', error_msgs[2]),
-                ('/paramerrors/one_positional_kwargs/foo', 'param1=foo&param2=bar&param3=baz', error_msgs[2]),
-                ('/paramerrors/no_positional', 'param1=foo', error_msgs[4]),
-                ('/paramerrors/no_positional_args/boo', 'param1=foo', error_msgs[4]),
-                ('/paramerrors/callable_object', 'param1=foo', error_msgs[4]),
-            ):
-            for show_mismatched_params in (True, False):
-                cherrypy.config.update({'request.show_mismatched_params': show_mismatched_params})
-                self.getPage(uri, method='POST', body=body)
-                self.assertStatus(400)
-                if show_mismatched_params:
-                    self.assertInBody(msg)
-                else:
-                    self.assertInBody("Bad Request")
-
-
-        # even if body parameters are wrong, if we get the uri wrong, then 
-        # it's a 404
-        for uri, body, msg in (
-                ('/paramerrors/one_positional?param2=foo', 'param1=foo', error_msgs[3]),
-                ('/paramerrors/one_positional/foo/bar', 'param2=foo', error_msgs[1]),
-                ('/paramerrors/one_positional_args/foo/bar?param2=foo', 'param3=foo', error_msgs[3]),
-                ('/paramerrors/one_positional_kwargs/foo/bar', 'param2=bar&param3=baz', error_msgs[1]),
-                ('/paramerrors/no_positional?param1=foo', 'param2=foo', error_msgs[3]),
-                ('/paramerrors/no_positional_args/boo?param2=foo', 'param1=foo', error_msgs[3]),
-                ('/paramerrors/callable_object?param2=bar', 'param1=foo', error_msgs[3]),
-            ):
-            for show_mismatched_params in (True, False):
-                cherrypy.config.update({'request.show_mismatched_params': show_mismatched_params})
-                self.getPage(uri, method='POST', body=body)
-                self.assertStatus(404)
-                if show_mismatched_params:
-                    self.assertInBody(msg)
-                else:
-                    self.assertInBody("Not Found")
-
-        # In the case that a handler raises a TypeError we should
-        # let that type error through.
-        for uri in (
-                '/paramerrors/raise_type_error',
-                '/paramerrors/raise_type_error_with_default_param?x=0',
-                '/paramerrors/raise_type_error_with_default_param?x=0&y=0',
-            ):
-            self.getPage(uri, method='GET')
-            self.assertStatus(500)
-            self.assertTrue('Client Error', self.body)
-
-    def testErrorHandling(self):
-        self.getPage("/error/missing")
-        self.assertStatus(404)
-        self.assertErrorPage(404, "The path '/error/missing' was not found.")
-        
-        ignore = helper.webtest.ignored_exceptions
-        ignore.append(ValueError)
-        try:
-            valerr = '\n    raise ValueError()\nValueError'
-            self.getPage("/error/page_method")
-            self.assertErrorPage(500, pattern=valerr)
-            
-            self.getPage("/error/page_yield")
-            self.assertErrorPage(500, pattern=valerr)
-            
-            if (cherrypy.server.protocol_version == "HTTP/1.0" or
-                getattr(cherrypy.server, "using_apache", False)):
-                self.getPage("/error/page_streamed")
-                # Because this error is raised after the response body has
-                # started, the status should not change to an error status.
-                self.assertStatus(200)
-                self.assertBody("word up")
-            else:
-                # Under HTTP/1.1, the chunked transfer-coding is used.
-                # The HTTP client will choke when the output is incomplete.
-                self.assertRaises((ValueError, IncompleteRead), self.getPage,
-                                  "/error/page_streamed")
-            
-            # No traceback should be present
-            self.getPage("/error/cause_err_in_finalize")
-            msg = "Illegal response status from server ('ZOO' is non-numeric)."
-            self.assertErrorPage(500, msg, None)
-        finally:
-            ignore.pop()
-        
-        # Test HTTPError with a reason-phrase in the status arg.
-        self.getPage('/error/reason_phrase')
-        self.assertStatus("410 Gone fishin'")
-        
-        # Test custom error page for a specific error.
-        self.getPage("/error/custom")
-        self.assertStatus(404)
-        self.assertBody("Hello, world\r\n" + (" " * 499))
-        
-        # Test custom error page for a specific error.
-        self.getPage("/error/custom?err=401")
-        self.assertStatus(401)
-        self.assertBody("Error 401 Unauthorized - Well, I'm very sorry but you haven't paid!")
-        
-        # Test default custom error page.
-        self.getPage("/error/custom_default")
-        self.assertStatus(500)
-        self.assertBody("Error 500 Internal Server Error - Well, I'm very sorry but you haven't paid!".ljust(513))
-        
-        # Test error in custom error page (ticket #305).
-        # Note that the message is escaped for HTML (ticket #310).
-        self.getPage("/error/noexist")
-        self.assertStatus(404)
-        msg = ("No, &lt;b&gt;really&lt;/b&gt;, not found!<br />"
-               "In addition, the custom error page failed:\n<br />"
-               "IOError: [Errno 2] No such file or directory: 'nonexistent.html'")
-        self.assertInBody(msg)
-        
-        if getattr(cherrypy.server, "using_apache", False):
-            pass
-        else:
-            # Test throw_errors (ticket #186).
-            self.getPage("/error/rethrow")
-            self.assertInBody("raise ValueError()")
-    
-    def testExpect(self):
-        e = ('Expect', '100-continue')
-        self.getPage("/headerelements/get_elements?headername=Expect", [e])
-        self.assertBody('100-continue')
-        
-        self.getPage("/expect/expectation_failed", [e])
-        self.assertStatus(417)
-    
-    def testHeaderElements(self):
-        # Accept-* header elements should be sorted, with most preferred first.
-        h = [('Accept', 'audio/*; q=0.2, audio/basic')]
-        self.getPage("/headerelements/get_elements?headername=Accept", h)
-        self.assertStatus(200)
-        self.assertBody("audio/basic\n"
-                        "audio/*;q=0.2")
-        
-        h = [('Accept', 'text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c')]
-        self.getPage("/headerelements/get_elements?headername=Accept", h)
-        self.assertStatus(200)
-        self.assertBody("text/x-c\n"
-                        "text/html\n"
-                        "text/x-dvi;q=0.8\n"
-                        "text/plain;q=0.5")
-        
-        # Test that more specific media ranges get priority.
-        h = [('Accept', 'text/*, text/html, text/html;level=1, */*')]
-        self.getPage("/headerelements/get_elements?headername=Accept", h)
-        self.assertStatus(200)
-        self.assertBody("text/html;level=1\n"
-                        "text/html\n"
-                        "text/*\n"
-                        "*/*")
-        
-        # Test Accept-Charset
-        h = [('Accept-Charset', 'iso-8859-5, unicode-1-1;q=0.8')]
-        self.getPage("/headerelements/get_elements?headername=Accept-Charset", h)
-        self.assertStatus("200 OK")
-        self.assertBody("iso-8859-5\n"
-                        "unicode-1-1;q=0.8")
-        
-        # Test Accept-Encoding
-        h = [('Accept-Encoding', 'gzip;q=1.0, identity; q=0.5, *;q=0')]
-        self.getPage("/headerelements/get_elements?headername=Accept-Encoding", h)
-        self.assertStatus("200 OK")
-        self.assertBody("gzip;q=1.0\n"
-                        "identity;q=0.5\n"
-                        "*;q=0")
-        
-        # Test Accept-Language
-        h = [('Accept-Language', 'da, en-gb;q=0.8, en;q=0.7')]
-        self.getPage("/headerelements/get_elements?headername=Accept-Language", h)
-        self.assertStatus("200 OK")
-        self.assertBody("da\n"
-                        "en-gb;q=0.8\n"
-                        "en;q=0.7")
-        
-        # Test malformed header parsing. See http://www.cherrypy.org/ticket/763.
-        self.getPage("/headerelements/get_elements?headername=Content-Type",
-                     # Note the illegal trailing ";"
-                     headers=[('Content-Type', 'text/html; charset=utf-8;')])
-        self.assertStatus(200)
-        self.assertBody("text/html;charset=utf-8")
-    
-    def test_repeated_headers(self):
-        # Test that two request headers are collapsed into one.
-        # See http://www.cherrypy.org/ticket/542.
-        self.getPage("/headers/Accept-Charset",
-                     headers=[("Accept-Charset", "iso-8859-5"),
-                              ("Accept-Charset", "unicode-1-1;q=0.8")])
-        self.assertBody("iso-8859-5, unicode-1-1;q=0.8")
-        
-        # Tests that each header only appears once, regardless of case.
-        self.getPage("/headers/doubledheaders")
-        self.assertBody("double header test")
-        hnames = [name.title() for name, val in self.headers]
-        for key in ['Content-Length', 'Content-Type', 'Date',
-                    'Expires', 'Location', 'Server']:
-            self.assertEqual(hnames.count(key), 1, self.headers)
-    
-    def test_encoded_headers(self):
-        # First, make sure the innards work like expected.
-        self.assertEqual(httputil.decode_TEXT(u"=?utf-8?q?f=C3=BCr?="), u"f\xfcr")
-        
-        if cherrypy.server.protocol_version == "HTTP/1.1":
-            # Test RFC-2047-encoded request and response header values
-            u = u'\u212bngstr\xf6m'
-            c = u"=E2=84=ABngstr=C3=B6m"
-            self.getPage("/headers/ifmatch", [('If-Match', u'=?utf-8?q?%s?=' % c)])
-            # The body should be utf-8 encoded.
-            self.assertBody("\xe2\x84\xabngstr\xc3\xb6m")
-            # But the Etag header should be RFC-2047 encoded (binary)
-            self.assertHeader("ETag", u'=?utf-8?b?4oSrbmdzdHLDtm0=?=')
-            
-            # Test a *LONG* RFC-2047-encoded request and response header value
-            self.getPage("/headers/ifmatch",
-                         [('If-Match', u'=?utf-8?q?%s?=' % (c * 10))])
-            self.assertBody("\xe2\x84\xabngstr\xc3\xb6m" * 10)
-            # Note: this is different output for Python3, but it decodes fine.
-            etag = self.assertHeader("ETag",
-                '=?utf-8?b?4oSrbmdzdHLDtm3ihKtuZ3N0csO2beKEq25nc3Ryw7Zt'
-                '4oSrbmdzdHLDtm3ihKtuZ3N0csO2beKEq25nc3Ryw7Zt'
-                '4oSrbmdzdHLDtm3ihKtuZ3N0csO2beKEq25nc3Ryw7Zt'
-                '4oSrbmdzdHLDtm0=?=')
-            self.assertEqual(httputil.decode_TEXT(etag), u * 10)
-    
-    def test_header_presence(self):
-        # If we don't pass a Content-Type header, it should not be present
-        # in cherrypy.request.headers
-        self.getPage("/headers/Content-Type",
-                     headers=[])
-        self.assertStatus(500)
-        
-        # If Content-Type is present in the request, it should be present in
-        # cherrypy.request.headers
-        self.getPage("/headers/Content-Type",
-                     headers=[("Content-type", "application/json")])
-        self.assertBody("application/json")
-    
-    def test_basic_HTTPMethods(self):
-        helper.webtest.methods_with_bodies = ("POST", "PUT", "PROPFIND")
-        
-        # Test that all defined HTTP methods work.
-        for m in defined_http_methods:
-            self.getPage("/method/", method=m)
-            
-            # HEAD requests should not return any body.
-            if m == "HEAD":
-                self.assertBody("")
-            elif m == "TRACE":
-                # Some HTTP servers (like modpy) have their own TRACE support
-                self.assertEqual(self.body[:5], "TRACE")
-            else:
-                self.assertBody(m)
-        
-        # Request a PUT method with a form-urlencoded body
-        self.getPage("/method/parameterized", method="PUT",
-                       body="data=on+top+of+other+things")
-        self.assertBody("on top of other things")
-        
-        # Request a PUT method with a file body
-        b = "one thing on top of another"
-        h = [("Content-Type", "text/plain"),
-             ("Content-Length", str(len(b)))]
-        self.getPage("/method/request_body", headers=h, method="PUT", body=b)
-        self.assertStatus(200)
-        self.assertBody(b)
-        
-        # Request a PUT method with a file body but no Content-Type.
-        # See http://www.cherrypy.org/ticket/790.
-        b = "one thing on top of another"
-        self.persistent = True
-        try:
-            conn = self.HTTP_CONN
-            conn.putrequest("PUT", "/method/request_body", skip_host=True)
-            conn.putheader("Host", self.HOST)
-            conn.putheader('Content-Length', str(len(b)))
-            conn.endheaders()
-            conn.send(b)
-            response = conn.response_class(conn.sock, method="PUT")
-            response.begin()
-            self.assertEqual(response.status, 200)
-            self.body = response.read()
-            self.assertBody(b)
-        finally:
-            self.persistent = False
-        
-        # Request a PUT method with no body whatsoever (not an empty one).
-        # See http://www.cherrypy.org/ticket/650.
-        # Provide a C-T or webtest will provide one (and a C-L) for us.
-        h = [("Content-Type", "text/plain")]
-        self.getPage("/method/reachable", headers=h, method="PUT")
-        self.assertStatus(411)
-        
-        # Request a custom method with a request body
-        b = ('<?xml version="1.0" encoding="utf-8" ?>\n\n'
-             '<propfind xmlns="DAV:"><prop><getlastmodified/>'
-             '</prop></propfind>')
-        h = [('Content-Type', 'text/xml'),
-             ('Content-Length', str(len(b)))]
-        self.getPage("/method/request_body", headers=h, method="PROPFIND", body=b)
-        self.assertStatus(200)
-        self.assertBody(b)
-        
-        # Request a disallowed method
-        self.getPage("/method/", method="LINK")
-        self.assertStatus(405)
-        
-        # Request an unknown method
-        self.getPage("/method/", method="SEARCH")
-        self.assertStatus(501)
-        
-        # For method dispatchers: make sure that an HTTP method doesn't
-        # collide with a virtual path atom. If you build HTTP-method
-        # dispatching into the core, rewrite these handlers to use
-        # your dispatch idioms.
-        self.getPage("/divorce/get?ID=13")
-        self.assertBody('Divorce document 13: empty')
-        self.assertStatus(200)
-        self.getPage("/divorce/", method="GET")
-        self.assertBody('<h1>Choose your document</h1>\n<ul>\n</ul>')
-        self.assertStatus(200)
-    
-    def test_CONNECT_method(self):
-        if getattr(cherrypy.server, "using_apache", False):
-            return self.skip("skipped due to known Apache differences... ")
-        
-        self.getPage("/method/", method="CONNECT")
-        self.assertBody("CONNECT")
-    
-    def testEmptyThreadlocals(self):
-        results = []
-        for x in xrange(20):
-            self.getPage("/threadlocal/")
-            results.append(self.body)
-        self.assertEqual(results, ["None"] * 20)
-
-
-if __name__ == '__main__':
-    helper.testmain()
--- a/bundled/cherrypy/cherrypy/test/test_routes.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import os
-curdir = os.path.join(os.getcwd(), os.path.dirname(__file__))
-
-import cherrypy
-
-
-def setup_server():
-
-    class Dummy:
-        def index(self):
-            return "I said good day!"
-    
-    class City:
-        
-        def __init__(self, name):
-            self.name = name
-            self.population = 10000
-        
-        def index(self, **kwargs):
-            return "Welcome to %s, pop. %s" % (self.name, self.population)
-        index._cp_config = {'tools.response_headers.on': True,
-                            'tools.response_headers.headers': [('Content-Language', 'en-GB')]}
-        
-        def update(self, **kwargs):
-            self.population = kwargs['pop']
-            return "OK"
-        
-    d = cherrypy.dispatch.RoutesDispatcher()
-    d.connect(name='hounslow', route='hounslow', controller=City('Hounslow'))
-    d.connect(name='surbiton', route='surbiton', controller=City('Surbiton'),
-              action='index', conditions=dict(method=['GET']))
-    d.mapper.connect('surbiton', controller='surbiton',
-                     action='update', conditions=dict(method=['POST']))
-    d.connect('main', ':action', controller=Dummy())
-    
-    conf = {'/': {'request.dispatch': d}}
-    cherrypy.tree.mount(root=None, config=conf)
-
-
-from cherrypy.test import helper
-
-class RoutesDispatchTest(helper.CPWebCase):
-
-    def test_Routes_Dispatch(self):
-        self.getPage("/hounslow")
-        self.assertStatus("200 OK")
-        self.assertBody("Welcome to Hounslow, pop. 10000")
-        
-        self.getPage("/foo")
-        self.assertStatus("404 Not Found")
-        
-        self.getPage("/surbiton")
-        self.assertStatus("200 OK")
-        self.assertBody("Welcome to Surbiton, pop. 10000")
-        
-        self.getPage("/surbiton", method="POST", body="pop=1327")
-        self.assertStatus("200 OK")
-        self.assertBody("OK")
-        self.getPage("/surbiton")
-        self.assertStatus("200 OK")
-        self.assertHeader("Content-Language", "en-GB")
-        self.assertBody("Welcome to Surbiton, pop. 1327")
-
-if __name__ == '__main__':
-    helper.testmain()
-
--- a/bundled/cherrypy/cherrypy/test/test_session.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,467 +0,0 @@
-from cherrypy.test import test
-test.prefer_parent_path()
-
-from httplib import HTTPConnection, HTTPSConnection
-import os
-localDir = os.path.dirname(__file__)
-import sys
-import threading
-import time
-
-import cherrypy
-from cherrypy.lib import sessions
-
-def http_methods_allowed(methods=['GET', 'HEAD']):
-    method = cherrypy.request.method.upper()
-    if method not in methods:
-        cherrypy.response.headers['Allow'] = ", ".join(methods)
-        raise cherrypy.HTTPError(405)
-
-cherrypy.tools.allow = cherrypy.Tool('on_start_resource', http_methods_allowed)
-
-
-def setup_server():
-    
-    class Root:
-        
-        _cp_config = {'tools.sessions.on': True,
-                      'tools.sessions.storage_type' : 'ram',
-                      'tools.sessions.storage_path' : localDir,
-                      'tools.sessions.timeout': (1.0 / 60),
-                      'tools.sessions.clean_freq': (1.0 / 60),
-                      }
-        
-        def clear(self):
-            cherrypy.session.cache.clear()
-        clear.exposed = True
-        
-        def data(self):
-            cherrypy.session['aha'] = 'foo'
-            return repr(cherrypy.session._data)
-        data.exposed = True
-        
-        def testGen(self):
-            counter = cherrypy.session.get('counter', 0) + 1
-            cherrypy.session['counter'] = counter
-            yield str(counter)
-        testGen.exposed = True
-        
-        def testStr(self):
-            counter = cherrypy.session.get('counter', 0) + 1
-            cherrypy.session['counter'] = counter
-            return str(counter)
-        testStr.exposed = True
-        
-        def setsessiontype(self, newtype):
-            self.__class__._cp_config.update({'tools.sessions.storage_type': newtype})
-            if hasattr(cherrypy, "session"):
-                del cherrypy.session
-            cls = getattr(sessions, newtype.title() + 'Session')
-            if cls.clean_thread:
-                cls.clean_thread.stop()
-                cls.clean_thread.unsubscribe()
-                del cls.clean_thread
-        setsessiontype.exposed = True
-        setsessiontype._cp_config = {'tools.sessions.on': False}
-        
-        def index(self):
-            sess = cherrypy.session
-            c = sess.get('counter', 0) + 1
-            time.sleep(0.01)
-            sess['counter'] = c
-            return str(c)
-        index.exposed = True
-        
-        def keyin(self, key):
-            return str(key in cherrypy.session)
-        keyin.exposed = True
-        
-        def delete(self):
-            cherrypy.session.delete()
-            sessions.expire()
-            return "done"
-        delete.exposed = True
-        
-        def delkey(self, key):
-            del cherrypy.session[key]
-            return "OK"
-        delkey.exposed = True
-        
-        def blah(self):
-            return self._cp_config['tools.sessions.storage_type']
-        blah.exposed = True
-        
-        def iredir(self):
-            raise cherrypy.InternalRedirect('/blah')
-        iredir.exposed = True
-        
-        def restricted(self):
-            return cherrypy.request.method
-        restricted.exposed = True
-        restricted._cp_config = {'tools.allow.on': True,
-                                 'tools.allow.methods': ['GET']}
-        
-        def regen(self):
-            cherrypy.tools.sessions.regenerate()
-            return "logged in"
-        regen.exposed = True
-        
-        def length(self):
-            return str(len(cherrypy.session))
-        length.exposed = True
-        
-        def session_cookie(self):
-            # Must load() to start the clean thread.
-            cherrypy.session.load()
-            return cherrypy.session.id
-        session_cookie.exposed = True
-        session_cookie._cp_config = {
-            'tools.sessions.path': '/session_cookie',
-            'tools.sessions.name': 'temp',
-            'tools.sessions.persistent': False}
-    
-    cherrypy.tree.mount(Root())
-
-
-from cherrypy.test import helper
-
-class SessionTest(helper.CPWebCase):
-    
-    def tearDown(self):
-        # Clean up sessions.
-        for fname in os.listdir(localDir):
-            if fname.startswith(sessions.FileSession.SESSION_PREFIX):
-                os.unlink(os.path.join(localDir, fname))
-    
-    def test_0_Session(self):
-        self.getPage('/setsessiontype/ram')
-        self.getPage('/clear')
-        
-        # Test that a normal request gets the same id in the cookies.
-        # Note: this wouldn't work if /data didn't load the session.
-        self.getPage('/data')
-        self.assertBody("{'aha': 'foo'}")
-        c = self.cookies[0]
-        self.getPage('/data', self.cookies)
-        self.assertEqual(self.cookies[0], c)
-        
-        self.getPage('/testStr')
-        self.assertBody('1')
-        cookie_parts = dict([p.strip().split('=')
-                             for p in self.cookies[0][1].split(";")])
-        # Assert there is an 'expires' param
-        self.assertEqual(set(cookie_parts.keys()),
-                         set(['session_id', 'expires', 'Path']))
-        self.getPage('/testGen', self.cookies)
-        self.assertBody('2')
-        self.getPage('/testStr', self.cookies)
-        self.assertBody('3')
-        self.getPage('/data', self.cookies)
-        self.assertBody("{'aha': 'foo', 'counter': 3}")
-        self.getPage('/length', self.cookies)
-        self.assertBody('2')
-        self.getPage('/delkey?key=counter', self.cookies)
-        self.assertStatus(200)
-        
-        self.getPage('/setsessiontype/file')
-        self.getPage('/testStr')
-        self.assertBody('1')
-        self.getPage('/testGen', self.cookies)
-        self.assertBody('2')
-        self.getPage('/testStr', self.cookies)
-        self.assertBody('3')
-        self.getPage('/delkey?key=counter', self.cookies)
-        self.assertStatus(200)
-        
-        # Wait for the session.timeout (1 second)
-        time.sleep(2)
-        self.getPage('/')
-        self.assertBody('1')
-        self.getPage('/length', self.cookies)
-        self.assertBody('1')
-        
-        # Test session __contains__
-        self.getPage('/keyin?key=counter', self.cookies)
-        self.assertBody("True")
-        cookieset1 = self.cookies
-        
-        # Make a new session and test __len__ again
-        self.getPage('/')
-        self.getPage('/length', self.cookies)
-        self.assertBody('2')
-        
-        # Test session delete
-        self.getPage('/delete', self.cookies)
-        self.assertBody("done")
-        self.getPage('/delete', cookieset1)
-        self.assertBody("done")
-        f = lambda: [x for x in os.listdir(localDir) if x.startswith('session-')]
-        self.assertEqual(f(), [])
-        
-        # Wait for the cleanup thread to delete remaining session files
-        self.getPage('/')
-        f = lambda: [x for x in os.listdir(localDir) if x.startswith('session-')]
-        self.assertNotEqual(f(), [])
-        time.sleep(2)
-        self.assertEqual(f(), [])
-    
-    def test_1_Ram_Concurrency(self):
-        self.getPage('/setsessiontype/ram')
-        self._test_Concurrency()
-    
-    def test_2_File_Concurrency(self):
-        self.getPage('/setsessiontype/file')
-        self._test_Concurrency()
-    
-    def _test_Concurrency(self):
-        client_thread_count = 5
-        request_count = 30
-        
-        # Get initial cookie
-        self.getPage("/")
-        self.assertBody("1")
-        cookies = self.cookies
-        
-        data_dict = {}
-        errors = []
-        
-        def request(index):
-            if self.scheme == 'https':
-                c = HTTPSConnection('%s:%s' % (self.interface(), self.PORT))
-            else:
-                c = HTTPConnection('%s:%s' % (self.interface(), self.PORT))
-            for i in range(request_count):
-                c.putrequest('GET', '/')
-                for k, v in cookies:
-                    c.putheader(k, v)
-                c.endheaders()
-                response = c.getresponse()
-                body = response.read()
-                if response.status != 200 or not body.isdigit():
-                    errors.append((response.status, body))
-                else:
-                    data_dict[index] = max(data_dict[index], int(body))
-                # Uncomment the following line to prove threads overlap.
-##                print index,
-        
-        # Start <request_count> requests from each of
-        # <client_thread_count> concurrent clients
-        ts = []
-        for c in range(client_thread_count):
-            data_dict[c] = 0
-            t = threading.Thread(target=request, args=(c,))
-            ts.append(t)
-            t.start()
-        
-        for t in ts:
-            t.join()
-        
-        hitcount = max(data_dict.values())
-        expected = 1 + (client_thread_count * request_count)
-        
-        for e in errors:
-            print(e)
-        self.assertEqual(hitcount, expected)
-    
-    def test_3_Redirect(self):
-        # Start a new session
-        self.getPage('/testStr')
-        self.getPage('/iredir', self.cookies)
-        self.assertBody("file")
-    
-    def test_4_File_deletion(self):
-        # Start a new session
-        self.getPage('/testStr')
-        # Delete the session file manually and retry.
-        id = self.cookies[0][1].split(";", 1)[0].split("=", 1)[1]
-        path = os.path.join(localDir, "session-" + id)
-        os.unlink(path)
-        self.getPage('/testStr', self.cookies)
-    
-    def test_5_Error_paths(self):
-        self.getPage('/unknown/page')
-        self.assertErrorPage(404, "The path '/unknown/page' was not found.")
-        
-        # Note: this path is *not* the same as above. The above
-        # takes a normal route through the session code; this one
-        # skips the session code's before_handler and only calls
-        # before_finalize (save) and on_end (close). So the session
-        # code has to survive calling save/close without init.
-        self.getPage('/restricted', self.cookies, method='POST')
-        self.assertErrorPage(405, "Specified method is invalid for this server.")
-    
-    def test_6_regenerate(self):
-        self.getPage('/testStr')
-        # grab the cookie ID
-        id1 = self.cookies[0][1].split(";", 1)[0].split("=", 1)[1]
-        self.getPage('/regen')
-        self.assertBody('logged in')
-        id2 = self.cookies[0][1].split(";", 1)[0].split("=", 1)[1]
-        self.assertNotEqual(id1, id2)
-        
-        self.getPage('/testStr')
-        # grab the cookie ID
-        id1 = self.cookies[0][1].split(";", 1)[0].split("=", 1)[1]
-        self.getPage('/testStr',
-                     headers=[('Cookie',
-                               'session_id=maliciousid; '
-                               'expires=Sat, 27 Oct 2017 04:18:28 GMT; Path=/;')])
-        id2 = self.cookies[0][1].split(";", 1)[0].split("=", 1)[1]
-        self.assertNotEqual(id1, id2)
-        self.assertNotEqual(id2, 'maliciousid')
-    
-    def test_7_session_cookies(self):
-        self.getPage('/setsessiontype/ram')
-        self.getPage('/clear')
-        self.getPage('/session_cookie')
-        # grab the cookie ID
-        cookie_parts = dict([p.strip().split('=') for p in self.cookies[0][1].split(";")])
-        # Assert there is no 'expires' param
-        self.assertEqual(set(cookie_parts.keys()), set(['temp', 'Path']))
-        id1 = cookie_parts['temp']
-        self.assertEqual(sessions.RamSession.cache.keys(), [id1])
-        
-        # Send another request in the same "browser session".
-        self.getPage('/session_cookie', self.cookies)
-        cookie_parts = dict([p.strip().split('=') for p in self.cookies[0][1].split(";")])
-        # Assert there is no 'expires' param
-        self.assertEqual(set(cookie_parts.keys()), set(['temp', 'Path']))
-        self.assertBody(id1)
-        self.assertEqual(sessions.RamSession.cache.keys(), [id1])
-        
-        # Simulate a browser close by just not sending the cookies
-        self.getPage('/session_cookie')
-        # grab the cookie ID
-        cookie_parts = dict([p.strip().split('=') for p in self.cookies[0][1].split(";")])
-        # Assert there is no 'expires' param
-        self.assertEqual(set(cookie_parts.keys()), set(['temp', 'Path']))
-        # Assert a new id has been generated...
-        id2 = cookie_parts['temp']
-        self.assertNotEqual(id1, id2)
-        self.assertEqual(set(sessions.RamSession.cache.keys()), set([id1, id2]))
-        
-        # Wait for the session.timeout on both sessions
-        time.sleep(2.5)
-        cache = sessions.RamSession.cache.keys()
-        if cache:
-            if cache == [id2]:
-                self.fail("The second session did not time out.")
-            else:
-                self.fail("Unknown session id in cache: %r", cache)
-
-
-import socket
-try:
-    import memcache
-    
-    host, port = '127.0.0.1', 11211
-    for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC,
-                                  socket.SOCK_STREAM):
-        af, socktype, proto, canonname, sa = res
-        s = None
-        try:
-            s = socket.socket(af, socktype, proto)
-            # See http://groups.google.com/group/cherrypy-users/
-            #        browse_frm/thread/bbfe5eb39c904fe0
-            s.settimeout(1.0)
-            s.connect((host, port))
-            s.close()
-        except socket.error:
-            if s:
-                s.close()
-            raise
-        break
-except (ImportError, socket.error):
-    class MemcachedSessionTest(helper.CPWebCase):
-        
-        def test(self):
-            return self.skip("memcached not reachable ")
-else:
-    class MemcachedSessionTest(helper.CPWebCase):
-        
-        def test_0_Session(self):
-            self.getPage('/setsessiontype/memcached')
-            
-            self.getPage('/testStr')
-            self.assertBody('1')
-            self.getPage('/testGen', self.cookies)
-            self.assertBody('2')
-            self.getPage('/testStr', self.cookies)
-            self.assertBody('3')
-            self.getPage('/length', self.cookies)
-            self.assertErrorPage(500)
-            self.assertInBody("NotImplementedError")
-            self.getPage('/delkey?key=counter', self.cookies)
-            self.assertStatus(200)
-            
-            # Wait for the session.timeout (1 second)
-            time.sleep(1.25)
-            self.getPage('/')
-            self.assertBody('1')
-            
-            # Test session __contains__
-            self.getPage('/keyin?key=counter', self.cookies)
-            self.assertBody("True")
-            
-            # Test session delete
-            self.getPage('/delete', self.cookies)
-            self.assertBody("done")
-        
-        def test_1_Concurrency(self):
-            client_thread_count = 5
-            request_count = 30
-            
-            # Get initial cookie
-            self.getPage("/")
-            self.assertBody("1")
-            cookies = self.cookies
-            
-            data_dict = {}
-            
-            def request(index):
-                for i in range(request_count):
-                    self.getPage("/", cookies)
-                    # Uncomment the following line to prove threads overlap.
-##                    print index,
-                if not self.body.isdigit():
-                    self.fail(self.body)
-                data_dict[index] = v = int(self.body)
-            
-            # Start <request_count> concurrent requests from
-            # each of <client_thread_count> clients
-            ts = []
-            for c in range(client_thread_count):
-                data_dict[c] = 0
-                t = threading.Thread(target=request, args=(c,))
-                ts.append(t)
-                t.start()
-            
-            for t in ts:
-                t.join()
-            
-            hitcount = max(data_dict.values())
-            expected = 1 + (client_thread_count * request_count)
-            self.assertEqual(hitcount, expected)
-        
-        def test_3_Redirect(self):
-            # Start a new session
-            self.getPage('/testStr')
-            self.getPage('/iredir', self.cookies)
-            self.assertBody("memcached")
-        
-        def test_5_Error_paths(self):
-            self.getPage('/unknown/page')
-            self.assertErrorPage(404, "The path '/unknown/page' was not found.")
-            
-            # Note: this path is *not* the same as above. The above
-            # takes a normal route through the session code; this one
-            # skips the session code's before_handler and only calls
-            # before_finalize (save) and on_end (close). So the session
-            # code has to survive calling save/close without init.
-            self.getPage('/restricted', self.cookies, method='POST')
-            self.assertErrorPage(405, "Specified method is invalid for this server.")
-
-
-
-if __name__ == "__main__":
-    helper.testmain()
--- a/bundled/cherrypy/cherrypy/test/test_sessionauthenticate.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import cherrypy
-
-def setup_server():
-    
-    def check(username, password):
-        # Dummy check_username_and_password function
-        if username != 'test' or password != 'password':
-            return u'Wrong login/password'
-    
-    def augment_params():
-        # A simple tool to add some things to request.params
-        # This is to check to make sure that session_auth can handle request
-        # params (ticket #780)
-        cherrypy.request.params["test"] = "test"
-
-    cherrypy.tools.augment_params = cherrypy.Tool('before_handler',
-             augment_params, None, priority=30)
-
-    class Test:
-        
-        _cp_config = {'tools.sessions.on': True,
-                      'tools.session_auth.on': True,
-                      'tools.session_auth.check_username_and_password': check,
-                      'tools.augment_params.on': True,
-                      }
-        
-        def index(self, **kwargs):
-            return "Hi %s, you are logged in" % cherrypy.request.login
-        index.exposed = True
-    
-    cherrypy.tree.mount(Test())
-
-
-from cherrypy.test import helper
-
-
-class SessionAuthenticateTest(helper.CPWebCase):
-    
-    def testSessionAuthenticate(self):
-        # request a page and check for login form
-        self.getPage('/')
-        self.assertInBody('<form method="post" action="do_login">')
-        
-        # setup credentials
-        login_body = 'username=test&password=password&from_page=/'
-        
-        # attempt a login
-        self.getPage('/do_login', method='POST', body=login_body)
-        self.assertStatus((302, 303))
-        
-        # get the page now that we are logged in
-        self.getPage('/', self.cookies)
-        self.assertBody('Hi test, you are logged in')
-        
-        # do a logout
-        self.getPage('/do_logout', self.cookies, method='POST')
-        self.assertStatus((302, 303))
-        
-        # verify we are logged out
-        self.getPage('/', self.cookies)
-        self.assertInBody('<form method="post" action="do_login">')
-
-
-if __name__ == "__main__":
-    helper.testmain()
-
--- a/bundled/cherrypy/cherrypy/test/test_states.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,445 +0,0 @@
-from httplib import BadStatusLine
-
-import os
-import sys
-import threading
-import time
-
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import cherrypy
-engine = cherrypy.engine
-thisdir = os.path.join(os.getcwd(), os.path.dirname(__file__))
-
-
-class Dependency:
-    
-    def __init__(self, bus):
-        self.bus = bus
-        self.running = False
-        self.startcount = 0
-        self.gracecount = 0
-        self.threads = {}
-    
-    def subscribe(self):
-        self.bus.subscribe('start', self.start)
-        self.bus.subscribe('stop', self.stop)
-        self.bus.subscribe('graceful', self.graceful)
-        self.bus.subscribe('start_thread', self.startthread)
-        self.bus.subscribe('stop_thread', self.stopthread)
-    
-    def start(self):
-        self.running = True
-        self.startcount += 1
-    
-    def stop(self):
-        self.running = False
-    
-    def graceful(self):
-        self.gracecount += 1
-    
-    def startthread(self, thread_id):
-        self.threads[thread_id] = None
-    
-    def stopthread(self, thread_id):
-        del self.threads[thread_id]
-
-db_connection = Dependency(engine)
-
-def setup_server():
-    class Root:
-        def index(self):
-            return "Hello World"
-        index.exposed = True
-        
-        def ctrlc(self):
-            raise KeyboardInterrupt()
-        ctrlc.exposed = True
-        
-        def graceful(self):
-            engine.graceful()
-            return "app was (gracefully) restarted succesfully"
-        graceful.exposed = True
-        
-        def block_explicit(self):
-            while True:
-                if cherrypy.response.timed_out:
-                    cherrypy.response.timed_out = False
-                    return "broken!"
-                time.sleep(0.01)
-        block_explicit.exposed = True
-        
-        def block_implicit(self):
-            time.sleep(0.5)
-            return "response.timeout = %s" % cherrypy.response.timeout
-        block_implicit.exposed = True
-
-    cherrypy.tree.mount(Root())
-    cherrypy.config.update({
-        'environment': 'test_suite',
-        'engine.deadlock_poll_freq': 0.1,
-        })
-
-    db_connection.subscribe()
-
-
-
-# ------------ Enough helpers. Time for real live test cases. ------------ #
-
-
-from cherrypy.test import helper
-
-class ServerStateTests(helper.CPWebCase):
-    
-    def setUp(self):
-        cherrypy.server.socket_timeout = 0.1
-    
-    def test_0_NormalStateFlow(self):
-        engine.stop()
-        # Our db_connection should not be running
-        self.assertEqual(db_connection.running, False)
-        self.assertEqual(db_connection.startcount, 1)
-        self.assertEqual(len(db_connection.threads), 0)
-        
-        # Test server start
-        engine.start()
-        self.assertEqual(engine.state, engine.states.STARTED)
-        
-        host = cherrypy.server.socket_host
-        port = cherrypy.server.socket_port
-        self.assertRaises(IOError, cherrypy._cpserver.check_port, host, port)
-        
-        # The db_connection should be running now
-        self.assertEqual(db_connection.running, True)
-        self.assertEqual(db_connection.startcount, 2)
-        self.assertEqual(len(db_connection.threads), 0)
-        
-        self.getPage("/")
-        self.assertBody("Hello World")
-        self.assertEqual(len(db_connection.threads), 1)
-        
-        # Test engine stop. This will also stop the HTTP server.
-        engine.stop()
-        self.assertEqual(engine.state, engine.states.STOPPED)
-        
-        # Verify that our custom stop function was called
-        self.assertEqual(db_connection.running, False)
-        self.assertEqual(len(db_connection.threads), 0)
-        
-        # Block the main thread now and verify that exit() works.
-        def exittest():
-            self.getPage("/")
-            self.assertBody("Hello World")
-            engine.exit()
-        cherrypy.server.start()
-        engine.start_with_callback(exittest)
-        engine.block()
-        self.assertEqual(engine.state, engine.states.EXITING)
-    
-    def test_1_Restart(self):
-        cherrypy.server.start()
-        engine.start()
-        
-        # The db_connection should be running now
-        self.assertEqual(db_connection.running, True)
-        grace = db_connection.gracecount
-        
-        self.getPage("/")
-        self.assertBody("Hello World")
-        self.assertEqual(len(db_connection.threads), 1)
-        
-        # Test server restart from this thread
-        engine.graceful()
-        self.assertEqual(engine.state, engine.states.STARTED)
-        self.getPage("/")
-        self.assertBody("Hello World")
-        self.assertEqual(db_connection.running, True)
-        self.assertEqual(db_connection.gracecount, grace + 1)
-        self.assertEqual(len(db_connection.threads), 1)
-        
-        # Test server restart from inside a page handler
-        self.getPage("/graceful")
-        self.assertEqual(engine.state, engine.states.STARTED)
-        self.assertBody("app was (gracefully) restarted succesfully")
-        self.assertEqual(db_connection.running, True)
-        self.assertEqual(db_connection.gracecount, grace + 2)
-        # Since we are requesting synchronously, is only one thread used?
-        # Note that the "/graceful" request has been flushed.
-        self.assertEqual(len(db_connection.threads), 0)
-        
-        engine.stop()
-        self.assertEqual(engine.state, engine.states.STOPPED)
-        self.assertEqual(db_connection.running, False)
-        self.assertEqual(len(db_connection.threads), 0)
-    
-    def test_2_KeyboardInterrupt(self):
-        # Raise a keyboard interrupt in the HTTP server's main thread.
-        # We must start the server in this, the main thread
-        engine.start()
-        cherrypy.server.start()
-        
-        self.persistent = True
-        try:
-            # Make the first request and assert there's no "Connection: close".
-            self.getPage("/")
-            self.assertStatus('200 OK')
-            self.assertBody("Hello World")
-            self.assertNoHeader("Connection")
-            
-            cherrypy.server.httpserver.interrupt = KeyboardInterrupt
-            engine.block()
-            
-            self.assertEqual(db_connection.running, False)
-            self.assertEqual(len(db_connection.threads), 0)
-            self.assertEqual(engine.state, engine.states.EXITING)
-        finally:
-            self.persistent = False
-        
-        # Raise a keyboard interrupt in a page handler; on multithreaded
-        # servers, this should occur in one of the worker threads.
-        # This should raise a BadStatusLine error, since the worker
-        # thread will just die without writing a response.
-        engine.start()
-        cherrypy.server.start()
-        
-        try:
-            self.getPage("/ctrlc")
-        except BadStatusLine:
-            pass
-        else:
-            print(self.body)
-            self.fail("AssertionError: BadStatusLine not raised")
-        
-        engine.block()
-        self.assertEqual(db_connection.running, False)
-        self.assertEqual(len(db_connection.threads), 0)
-    
-    def test_3_Deadlocks(self):
-        cherrypy.config.update({'response.timeout': 0.2})
-        
-        engine.start()
-        cherrypy.server.start()
-        try:
-            self.assertNotEqual(engine.timeout_monitor.thread, None)
-            
-            # Request a "normal" page.
-            self.assertEqual(engine.timeout_monitor.servings, [])
-            self.getPage("/")
-            self.assertBody("Hello World")
-            # request.close is called async.
-            while engine.timeout_monitor.servings:
-                print ".",
-                time.sleep(0.01)
-            
-            # Request a page that explicitly checks itself for deadlock.
-            # The deadlock_timeout should be 2 secs.
-            self.getPage("/block_explicit")
-            self.assertBody("broken!")
-            
-            # Request a page that implicitly breaks deadlock.
-            # If we deadlock, we want to touch as little code as possible,
-            # so we won't even call handle_error, just bail ASAP.
-            self.getPage("/block_implicit")
-            self.assertStatus(500)
-            self.assertInBody("raise cherrypy.TimeoutError()")
-        finally:
-            engine.exit()
-    
-    def test_4_Autoreload(self):
-        # Start the demo script in a new process
-        p = helper.CPProcess(ssl=(self.scheme.lower()=='https'))
-        p.write_conf(
-                extra='test_case_name: "test_4_Autoreload"')
-        p.start(imports='cherrypy.test.test_states_demo')
-        try:
-            self.getPage("/start")
-            start = float(self.body)
-            
-            # Give the autoreloader time to cache the file time.
-            time.sleep(2)
-            
-            # Touch the file
-            os.utime(os.path.join(thisdir, "test_states_demo.py"), None)
-            
-            # Give the autoreloader time to re-exec the process
-            time.sleep(2)
-            host = cherrypy.server.socket_host
-            port = cherrypy.server.socket_port
-            cherrypy._cpserver.wait_for_occupied_port(host, port)
-            
-            self.getPage("/start")
-            self.assert_(float(self.body) > start)
-        finally:
-            # Shut down the spawned process
-            self.getPage("/exit")
-        p.join()
-    
-    def test_5_Start_Error(self):
-        # If a process errors during start, it should stop the engine
-        # and exit with a non-zero exit code.
-        p = helper.CPProcess(ssl=(self.scheme.lower()=='https'),
-                             wait=True)
-        p.write_conf(
-                extra="""starterror: True
-test_case_name: "test_5_Start_Error"
-"""
-        )
-        p.start(imports='cherrypy.test.test_states_demo')
-        if p.exit_code == 0:
-            self.fail("Process failed to return nonzero exit code.")
-
-
-class PluginTests(helper.CPWebCase):
-    
-    def test_daemonize(self):
-        if os.name not in ['posix']: 
-            return self.skip("skipped (not on posix) ")
-        self.HOST = '127.0.0.1'
-        self.PORT = 8081
-        # Spawn the process and wait, when this returns, the original process
-        # is finished.  If it daemonized properly, we should still be able
-        # to access pages.
-        p = helper.CPProcess(ssl=(self.scheme.lower()=='https'),
-                             wait=True, daemonize=True,
-                             socket_host='127.0.0.1',
-                             socket_port=8081)
-        p.write_conf(
-             extra='test_case_name: "test_daemonize"')
-        p.start(imports='cherrypy.test.test_states_demo')
-        try:
-            # Just get the pid of the daemonization process.
-            self.getPage("/pid")
-            self.assertStatus(200)
-            page_pid = int(self.body)
-            self.assertEqual(page_pid, p.get_pid())
-        finally:
-            # Shut down the spawned process
-            self.getPage("/exit")
-        p.join()
-        
-        # Wait until here to test the exit code because we want to ensure
-        # that we wait for the daemon to finish running before we fail.
-        if p.exit_code != 0:
-            self.fail("Daemonized parent process failed to exit cleanly.")
-
-
-class SignalHandlingTests(helper.CPWebCase):
-    
-    def test_SIGHUP_tty(self):
-        # When not daemonized, SIGHUP should shut down the server.
-        try:
-            from signal import SIGHUP
-        except ImportError:
-            return self.skip("skipped (no SIGHUP) ")
-        
-        # Spawn the process.
-        p = helper.CPProcess(ssl=(self.scheme.lower()=='https'))
-        p.write_conf(
-                extra='test_case_name: "test_SIGHUP_tty"')
-        p.start(imports='cherrypy.test.test_states_demo')
-        # Send a SIGHUP
-        os.kill(p.get_pid(), SIGHUP)
-        # This might hang if things aren't working right, but meh.
-        p.join()
-    
-    def test_SIGHUP_daemonized(self):
-        # When daemonized, SIGHUP should restart the server.
-        try:
-            from signal import SIGHUP
-        except ImportError:
-            return self.skip("skipped (no SIGHUP) ")
-        
-        if os.name not in ['posix']: 
-            return self.skip("skipped (not on posix) ")
-        
-        # Spawn the process and wait, when this returns, the original process
-        # is finished.  If it daemonized properly, we should still be able
-        # to access pages.
-        p = helper.CPProcess(ssl=(self.scheme.lower()=='https'),
-                             wait=True, daemonize=True)
-        p.write_conf(
-             extra='test_case_name: "test_SIGHUP_daemonized"')
-        p.start(imports='cherrypy.test.test_states_demo')
-        
-        pid = p.get_pid()
-        try:
-            # Send a SIGHUP
-            os.kill(pid, SIGHUP)
-            # Give the server some time to restart
-            time.sleep(2)
-            self.getPage("/pid")
-            self.assertStatus(200)
-            new_pid = int(self.body)
-            self.assertNotEqual(new_pid, pid)
-        finally:
-            # Shut down the spawned process
-            self.getPage("/exit")
-        p.join()
-    
-    def test_SIGTERM(self):
-        # SIGTERM should shut down the server whether daemonized or not.
-        try:
-            from signal import SIGTERM
-        except ImportError:
-            return self.skip("skipped (no SIGTERM) ")
-        
-        try:
-            from os import kill
-        except ImportError:
-            return self.skip("skipped (no os.kill) ")
-        
-        # Spawn a normal, undaemonized process.
-        p = helper.CPProcess(ssl=(self.scheme.lower()=='https'))
-        p.write_conf(
-                extra='test_case_name: "test_SIGTERM"')
-        p.start(imports='cherrypy.test.test_states_demo')
-        # Send a SIGTERM
-        os.kill(p.get_pid(), SIGTERM)
-        # This might hang if things aren't working right, but meh.
-        p.join()
-        
-        if os.name in ['posix']: 
-            # Spawn a daemonized process and test again.
-            p = helper.CPProcess(ssl=(self.scheme.lower()=='https'),
-                                 wait=True, daemonize=True)
-            p.write_conf(
-                 extra='test_case_name: "test_SIGTERM_2"')
-            p.start(imports='cherrypy.test.test_states_demo')
-            # Send a SIGTERM
-            os.kill(p.get_pid(), SIGTERM)
-            # This might hang if things aren't working right, but meh.
-            p.join()
-    
-    def test_signal_handler_unsubscribe(self):
-        try:
-            from signal import SIGTERM
-        except ImportError:
-            return self.skip("skipped (no SIGTERM) ")
-        
-        try:
-            from os import kill
-        except ImportError:
-            return self.skip("skipped (no os.kill) ")
-        
-        # Spawn a normal, undaemonized process.
-        p = helper.CPProcess(ssl=(self.scheme.lower()=='https'))
-        p.write_conf(
-            extra="""unsubsig: True
-test_case_name: "test_signal_handler_unsubscribe"
-""")
-        p.start(imports='cherrypy.test.test_states_demo')
-        # Send a SIGTERM
-        os.kill(p.get_pid(), SIGTERM)
-        # This might hang if things aren't working right, but meh.
-        p.join()
-        
-        # Assert the old handler ran.
-        target_line = open(p.error_log, 'rb').readlines()[-10]
-        if not "I am an old SIGTERM handler." in target_line:
-            self.fail("Old SIGTERM handler did not run.\n%r" % target_line)
-
-
-if __name__ == "__main__":
-    helper.testmain()
-
--- a/bundled/cherrypy/cherrypy/test/test_states_demo.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-import os
-import sys
-import time
-starttime = time.time()
-
-import cherrypy
-
-
-class Root:
-    
-    def index(self):
-        return "Hello World"
-    index.exposed = True
-    
-    def mtimes(self):
-        return repr(cherrypy.engine.publish("Autoreloader", "mtimes"))
-    mtimes.exposed = True
-    
-    def pid(self):
-        return str(os.getpid())
-    pid.exposed = True
-    
-    def start(self):
-        return repr(starttime)
-    start.exposed = True
-    
-    def exit(self):
-        # This handler might be called before the engine is STARTED if an
-        # HTTP worker thread handles it before the HTTP server returns
-        # control to engine.start. We avoid that race condition here
-        # by waiting for the Bus to be STARTED.
-        cherrypy.engine.wait(state=cherrypy.engine.states.STARTED)
-        cherrypy.engine.exit()
-    exit.exposed = True
-    
-
-def unsub_sig():
-    cherrypy.log("unsubsig: %s" % cherrypy.config.get('unsubsig', False))
-    if cherrypy.config.get('unsubsig', False):
-        cherrypy.log("Unsubscribing the default cherrypy signal handler")
-        cherrypy.engine.signal_handler.unsubscribe()
-    try:
-        from signal import signal, SIGTERM
-    except ImportError:
-        pass
-    else:
-        def old_term_handler(signum=None, frame=None):
-            cherrypy.log("I am an old SIGTERM handler.")
-            sys.exit(0)
-        cherrypy.log("Subscribing the new one.")
-        signal(SIGTERM, old_term_handler)
-cherrypy.engine.subscribe('start', unsub_sig, priority=100)
-
-
-def starterror():
-    if cherrypy.config.get('starterror', False):
-        zerodiv = 1 / 0
-cherrypy.engine.subscribe('start', starterror, priority=6)
-
-def log_test_case_name():
-    if cherrypy.config.get('test_case_name', False):
-        cherrypy.log("STARTED FROM: %s" % cherrypy.config.get('test_case_name'))
-cherrypy.engine.subscribe('start', log_test_case_name, priority=6)
-
-
-cherrypy.tree.mount(Root(), '/', {'/': {}})
--- a/bundled/cherrypy/cherrypy/test/test_static.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,308 +0,0 @@
-from cherrypy.test import test
-test.prefer_parent_path()
-
-from httplib import HTTPConnection, HTTPSConnection
-try:
-    import cStringIO as StringIO
-except ImportError:
-    import StringIO
-
-import os
-curdir = os.path.join(os.getcwd(), os.path.dirname(__file__))
-has_space_filepath = os.path.join(curdir, 'static', 'has space.html')
-bigfile_filepath = os.path.join(curdir, "static", "bigfile.log")
-BIGFILE_SIZE = 1024 * 1024
-import threading
-
-import cherrypy
-from cherrypy.lib import static
-
-def setup_server():
-    if not os.path.exists(has_space_filepath):
-        open(has_space_filepath, 'wb').write('Hello, world\r\n')
-    if not os.path.exists(bigfile_filepath):
-        open(bigfile_filepath, 'wb').write("x" * BIGFILE_SIZE)
-    
-    class Root:
-        
-        def bigfile(self):
-            from cherrypy.lib import static
-            self.f = static.serve_file(bigfile_filepath)
-            return self.f
-        bigfile.exposed = True
-        bigfile._cp_config = {'response.stream': True}
-        
-        def tell(self):
-            if self.f.input.closed:
-                return ''
-            return repr(self.f.input.tell()).rstrip('L')
-        tell.exposed = True
-        
-        def fileobj(self):
-            f = open(os.path.join(curdir, 'style.css'), 'rb')
-            return static.serve_fileobj(f, content_type='text/css')
-        fileobj.exposed = True
-        
-        def stringio(self):
-            f = StringIO.StringIO('Fee\nfie\nfo\nfum')
-            return static.serve_fileobj(f, content_type='text/plain')
-        stringio.exposed = True
-    
-    class Static:
-        
-        def index(self):
-            return 'You want the Baron? You can have the Baron!'
-        index.exposed = True
-        
-        def dynamic(self):
-            return "This is a DYNAMIC page"
-        dynamic.exposed = True
-    
-    
-    root = Root()
-    root.static = Static()
-    
-    rootconf = {
-        '/static': {
-            'tools.staticdir.on': True,
-            'tools.staticdir.dir': 'static',
-            'tools.staticdir.root': curdir,
-        },
-        '/style.css': {
-            'tools.staticfile.on': True,
-            'tools.staticfile.filename': os.path.join(curdir, 'style.css'),
-        },
-        '/docroot': {
-            'tools.staticdir.on': True,
-            'tools.staticdir.root': curdir,
-            'tools.staticdir.dir': 'static',
-            'tools.staticdir.index': 'index.html',
-        },
-        '/error': {
-            'tools.staticdir.on': True,
-            'request.show_tracebacks': True,
-        },
-        }
-    rootApp = cherrypy.Application(root)
-    rootApp.merge(rootconf)
-    
-    test_app_conf = {
-        '/test': {
-            'tools.staticdir.index': 'index.html',
-            'tools.staticdir.on': True,
-            'tools.staticdir.root': curdir,
-            'tools.staticdir.dir': 'static',
-            },
-        }
-    testApp = cherrypy.Application(Static())
-    testApp.merge(test_app_conf)
-    
-    vhost = cherrypy._cpwsgi.VirtualHost(rootApp, {'virt.net': testApp})
-    cherrypy.tree.graft(vhost)
-
-
-def teardown_server():
-    for f in (has_space_filepath, bigfile_filepath):
-        if os.path.exists(f):
-            try:
-                os.unlink(f)
-            except:
-                pass
-
-
-
-from cherrypy.test import helper
-
-class StaticTest(helper.CPWebCase):
-    
-    def testStatic(self):
-        self.getPage("/static/index.html")
-        self.assertStatus('200 OK')
-        self.assertHeader('Content-Type', 'text/html')
-        self.assertBody('Hello, world\r\n')
-        
-        # Using a staticdir.root value in a subdir...
-        self.getPage("/docroot/index.html")
-        self.assertStatus('200 OK')
-        self.assertHeader('Content-Type', 'text/html')
-        self.assertBody('Hello, world\r\n')
-        
-        # Check a filename with spaces in it
-        self.getPage("/static/has%20space.html")
-        self.assertStatus('200 OK')
-        self.assertHeader('Content-Type', 'text/html')
-        self.assertBody('Hello, world\r\n')
-        
-        self.getPage("/style.css")
-        self.assertStatus('200 OK')
-        self.assertHeader('Content-Type', 'text/css')
-        # Note: The body should be exactly 'Dummy stylesheet\n', but
-        #   unfortunately some tools such as WinZip sometimes turn \n
-        #   into \r\n on Windows when extracting the CherryPy tarball so
-        #   we just check the content
-        self.assertMatchesBody('^Dummy stylesheet')
-    
-    def test_fallthrough(self):
-        # Test that NotFound will then try dynamic handlers (see [878]).
-        self.getPage("/static/dynamic")
-        self.assertBody("This is a DYNAMIC page")
-        
-        # Check a directory via fall-through to dynamic handler.
-        self.getPage("/static/")
-        self.assertStatus('200 OK')
-        self.assertHeader('Content-Type', 'text/html;charset=utf-8')
-        self.assertBody('You want the Baron? You can have the Baron!')
-    
-    def test_index(self):
-        # Check a directory via "staticdir.index".
-        self.getPage("/docroot/")
-        self.assertStatus('200 OK')
-        self.assertHeader('Content-Type', 'text/html')
-        self.assertBody('Hello, world\r\n')
-        # The same page should be returned even if redirected.
-        self.getPage("/docroot")
-        self.assertStatus(301)
-        self.assertHeader('Location', '%s/docroot/' % self.base())
-        self.assertMatchesBody("This resource .* <a href='%s/docroot/'>"
-                               "%s/docroot/</a>." % (self.base(), self.base()))
-    
-    def test_config_errors(self):
-        # Check that we get an error if no .file or .dir
-        self.getPage("/error/thing.html")
-        self.assertErrorPage(500)
-        self.assertInBody("TypeError: staticdir() takes at least 2 "
-                          "arguments (0 given)")
-    
-    def test_security(self):
-        # Test up-level security
-        self.getPage("/static/../../test/style.css")
-        self.assertStatus((400, 403))
-    
-    def test_modif(self):
-        # Test modified-since on a reasonably-large file
-        self.getPage("/static/dirback.jpg")
-        self.assertStatus("200 OK")
-        lastmod = ""
-        for k, v in self.headers:
-            if k == 'Last-Modified':
-                lastmod = v
-        ims = ("If-Modified-Since", lastmod)
-        self.getPage("/static/dirback.jpg", headers=[ims])
-        self.assertStatus(304)
-        self.assertNoHeader("Content-Type")
-        self.assertNoHeader("Content-Length")
-        self.assertNoHeader("Content-Disposition")
-        self.assertBody("")
-    
-    def test_755_vhost(self):
-        self.getPage("/test/", [('Host', 'virt.net')])
-        self.assertStatus(200)
-        self.getPage("/test", [('Host', 'virt.net')])
-        self.assertStatus(301)
-        self.assertHeader('Location', self.scheme + '://virt.net/test/')
-    
-    def test_serve_fileobj(self):
-        self.getPage("/fileobj")
-        self.assertStatus('200 OK')
-        self.assertHeader('Content-Type', 'text/css;charset=utf-8')
-        self.assertMatchesBody('^Dummy stylesheet')
-    
-    def test_serve_stringio(self):
-        self.getPage("/stringio")
-        self.assertStatus('200 OK')
-        self.assertHeader('Content-Type', 'text/plain;charset=utf-8')
-        self.assertHeader('Content-Length', 14)
-        self.assertMatchesBody('Fee\nfie\nfo\nfum')
-    
-    def test_file_stream(self):
-        if cherrypy.server.protocol_version != "HTTP/1.1":
-            return self.skip()
-        
-        self.PROTOCOL = "HTTP/1.1"
-        
-        # Make an initial request
-        self.persistent = True
-        conn = self.HTTP_CONN
-        conn.putrequest("GET", "/bigfile", skip_host=True)
-        conn.putheader("Host", self.HOST)
-        conn.endheaders()
-        response = conn.response_class(conn.sock, method="GET")
-        response.begin()
-        self.assertEqual(response.status, 200)
-        
-        body = ''
-        remaining = BIGFILE_SIZE
-        while remaining > 0:
-            data = response.fp.read(65536)
-            if not data:
-                break
-            body += data
-            remaining -= len(data)
-            
-            if self.scheme == "https":
-                newconn = HTTPSConnection
-            else:
-                newconn = HTTPConnection
-            s, h, b = helper.webtest.openURL(
-                "/tell", headers=[], host=self.HOST, port=self.PORT,
-                http_conn=newconn)
-            if not b:
-                # The file was closed on the server.
-                tell_position = BIGFILE_SIZE
-            else:
-                tell_position = int(b)
-            
-            expected = len(body)
-            if tell_position >= BIGFILE_SIZE:
-                # We can't exactly control how much content the server asks for.
-                # Fudge it by only checking the first half of the reads.
-                if expected < (BIGFILE_SIZE / 2):
-                    self.fail(
-                        "The file should have advanced to position %r, but has "
-                        "already advanced to the end of the file. It may not be "
-                        "streamed as intended, or at the wrong chunk size (64k)" %
-                        expected)
-            elif tell_position < expected:
-                self.fail(
-                    "The file should have advanced to position %r, but has "
-                    "only advanced to position %r. It may not be streamed "
-                    "as intended, or at the wrong chunk size (65536)" %
-                    (expected, tell_position))
-        
-        if body != "x" * BIGFILE_SIZE:
-            self.fail("Body != 'x' * %d. Got %r instead (%d bytes)." %
-                      (BIGFILE_SIZE, body[:50], len(body)))
-        conn.close()
-    
-    def test_file_stream_deadlock(self):
-        if cherrypy.server.protocol_version != "HTTP/1.1":
-            return self.skip()
-        
-        self.PROTOCOL = "HTTP/1.1"
-        
-        # Make an initial request but abort early.
-        self.persistent = True
-        conn = self.HTTP_CONN
-        conn.putrequest("GET", "/bigfile", skip_host=True)
-        conn.putheader("Host", self.HOST)
-        conn.endheaders()
-        response = conn.response_class(conn.sock, method="GET")
-        response.begin()
-        self.assertEqual(response.status, 200)
-        body = response.fp.read(65536)
-        if body != "x" * 65536:
-            self.fail("Body != 'x' * %d. Got %r instead (%d bytes)." %
-                      (65536, body[:50], len(body)))
-        response.close()
-        conn.close()
-        
-        # Make a second request, which should fetch the whole file.
-        self.persistent = False
-        self.getPage("/bigfile")
-        if self.body != "x" * BIGFILE_SIZE:
-            self.fail("Body != 'x' * %d. Got %r instead (%d bytes)." %
-                      (BIGFILE_SIZE, self.body[:50], len(body)))
-
-
-if __name__ == "__main__":
-    helper.testmain()
--- a/bundled/cherrypy/cherrypy/test/test_tools.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,405 +0,0 @@
-"""Test the various means of instantiating and invoking tools."""
-
-import gzip
-try:
-    from cStringIO import StringIO
-except ImportError:
-    from StringIO import StringIO
-import sys
-from httplib import IncompleteRead
-import time
-timeout = 0.2
-
-import types
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import cherrypy
-from cherrypy import tools
-
-
-europoundUnicode = u'\x80\xa3'
-
-def setup_server():
-    
-    # Put check_access in a custom toolbox with its own namespace
-    myauthtools = cherrypy._cptools.Toolbox("myauth")
-    
-    def check_access(default=False):
-        if not getattr(cherrypy.request, "userid", default):
-            raise cherrypy.HTTPError(401)
-    myauthtools.check_access = cherrypy.Tool('before_request_body', check_access)
-    
-    def numerify():
-        def number_it(body):
-            for chunk in body:
-                for k, v in cherrypy.request.numerify_map:
-                    chunk = chunk.replace(k, v)
-                yield chunk
-        cherrypy.response.body = number_it(cherrypy.response.body)
-    
-    class NumTool(cherrypy.Tool):
-        def _setup(self):
-            def makemap():
-                m = self._merged_args().get("map", {})
-                cherrypy.request.numerify_map = m.items()
-            cherrypy.request.hooks.attach('on_start_resource', makemap)
-            
-            def critical():
-                cherrypy.request.error_response = cherrypy.HTTPError(502).set_response
-            critical.failsafe = True
-            
-            cherrypy.request.hooks.attach('on_start_resource', critical)
-            cherrypy.request.hooks.attach(self._point, self.callable)
-    
-    tools.numerify = NumTool('before_finalize', numerify)
-    
-    # It's not mandatory to inherit from cherrypy.Tool.
-    class NadsatTool:
-        
-        def __init__(self):
-            self.ended = {}
-            self._name = "nadsat"
-        
-        def nadsat(self):
-            def nadsat_it_up(body):
-                for chunk in body:
-                    chunk = chunk.replace("good", "horrorshow")
-                    chunk = chunk.replace("piece", "lomtick")
-                    yield chunk
-            cherrypy.response.body = nadsat_it_up(cherrypy.response.body)
-        nadsat.priority = 0
-        
-        def cleanup(self):
-            # This runs after the request has been completely written out.
-            cherrypy.response.body = "razdrez"
-            id = cherrypy.request.params.get("id")
-            if id:
-                self.ended[id] = True
-        cleanup.failsafe = True
-        
-        def _setup(self):
-            cherrypy.request.hooks.attach('before_finalize', self.nadsat)
-            cherrypy.request.hooks.attach('on_end_request', self.cleanup)
-    tools.nadsat = NadsatTool()
-    
-    def pipe_body():
-        cherrypy.request.process_request_body = False
-        clen = int(cherrypy.request.headers['Content-Length'])
-        cherrypy.request.body = cherrypy.request.rfile.read(clen)
-    
-    # Assert that we can use a callable object instead of a function.
-    class Rotator(object):
-        def __call__(self, scale):
-            r = cherrypy.response
-            r.collapse_body()
-            r.body = [chr((ord(x) + scale) % 256) for x in r.body[0]]
-    cherrypy.tools.rotator = cherrypy.Tool('before_finalize', Rotator())
-    
-    def stream_handler(next_handler, *args, **kwargs):
-        cherrypy.response.output = o = StringIO()
-        try:
-            response = next_handler(*args, **kwargs)
-            # Ignore the response and return our accumulated output instead.
-            return o.getvalue()
-        finally:
-            o.close()
-    cherrypy.tools.streamer = cherrypy._cptools.HandlerWrapperTool(stream_handler)
-    
-    class Root:
-        def index(self):
-            return "Howdy earth!"
-        index.exposed = True
-        
-        def tarfile(self):
-            cherrypy.response.output.write('I am ')
-            cherrypy.response.output.write('a tarfile')
-        tarfile.exposed = True
-        tarfile._cp_config = {'tools.streamer.on': True}
-        
-        def euro(self):
-            hooks = list(cherrypy.request.hooks['before_finalize'])
-            hooks.sort()
-            cbnames = [x.callback.__name__ for x in hooks]
-            assert cbnames == ['gzip'], cbnames
-            priorities = [x.priority for x in hooks]
-            assert priorities == [80], priorities
-            yield u"Hello,"
-            yield u"world"
-            yield europoundUnicode
-        euro.exposed = True
-        
-        # Bare hooks
-        def pipe(self):
-            return cherrypy.request.body
-        pipe.exposed = True
-        pipe._cp_config = {'hooks.before_request_body': pipe_body}
-        
-        # Multiple decorators; include kwargs just for fun.
-        # Note that rotator must run before gzip.
-        def decorated_euro(self, *vpath):
-            yield u"Hello,"
-            yield u"world"
-            yield europoundUnicode
-        decorated_euro.exposed = True
-        decorated_euro = tools.gzip(compress_level=6)(decorated_euro)
-        decorated_euro = tools.rotator(scale=3)(decorated_euro)
-    
-    root = Root()
-    
-    
-    class TestType(type):
-        """Metaclass which automatically exposes all functions in each subclass,
-        and adds an instance of the subclass as an attribute of root.
-        """
-        def __init__(cls, name, bases, dct):
-            type.__init__(cls, name, bases, dct)
-            for value in dct.itervalues():
-                if isinstance(value, types.FunctionType):
-                    value.exposed = True
-            setattr(root, name.lower(), cls())
-    class Test(object):
-        __metaclass__ = TestType
-    
-    
-    # METHOD ONE:
-    # Declare Tools in _cp_config
-    class Demo(Test):
-        
-        _cp_config = {"tools.nadsat.on": True}
-        
-        def index(self, id=None):
-            return "A good piece of cherry pie"
-        
-        def ended(self, id):
-            return repr(tools.nadsat.ended[id])
-        
-        def err(self, id=None):
-            raise ValueError()
-        
-        def errinstream(self, id=None):
-            yield "nonconfidential"
-            raise ValueError()
-            yield "confidential"
-        
-        # METHOD TWO: decorator using Tool()
-        # We support Python 2.3, but the @-deco syntax would look like this:
-        # @tools.check_access()
-        def restricted(self):
-            return "Welcome!"
-        restricted = myauthtools.check_access()(restricted)
-        userid = restricted
-        
-        def err_in_onstart(self):
-            return "success!"
-        
-        def stream(self, id=None):
-            for x in xrange(100000000):
-                yield str(x)
-        stream._cp_config = {'response.stream': True}
-    
-    
-    conf = {
-        # METHOD THREE:
-        # Declare Tools in detached config
-        '/demo': {
-            'tools.numerify.on': True,
-            'tools.numerify.map': {"pie": "3.14159"},
-        },
-        '/demo/restricted': {
-            'request.show_tracebacks': False,
-        },
-        '/demo/userid': {
-            'request.show_tracebacks': False,
-            'myauth.check_access.default': True,
-        },
-        '/demo/errinstream': {
-            'response.stream': True,
-        },
-        '/demo/err_in_onstart': {
-            # Because this isn't a dict, on_start_resource will error.
-            'tools.numerify.map': "pie->3.14159"
-        },
-        # Combined tools
-        '/euro': {
-            'tools.gzip.on': True,
-            'tools.encode.on': True,
-        },
-        # Priority specified in config
-        '/decorated_euro/subpath': {
-            'tools.gzip.priority': 10,
-        },
-        # Handler wrappers
-        '/tarfile': {'tools.streamer.on': True}
-    }
-    app = cherrypy.tree.mount(root, config=conf)
-    app.request_class.namespaces['myauth'] = myauthtools
-    
-    if sys.version_info >= (2, 5):
-        from cherrypy.test import py25
-        root.tooldecs = py25.ToolExamples()
-
-
-#                             Client-side code                             #
-
-from cherrypy.test import helper
-
-
-class ToolTests(helper.CPWebCase):
-    
-    def testHookErrors(self):
-        self.getPage("/demo/?id=1")
-        # If body is "razdrez", then on_end_request is being called too early.
-        self.assertBody("A horrorshow lomtick of cherry 3.14159")
-        # If this fails, then on_end_request isn't being called at all.
-        time.sleep(0.1)
-        self.getPage("/demo/ended/1")
-        self.assertBody("True")
-        
-        valerr = '\n    raise ValueError()\nValueError'
-        self.getPage("/demo/err?id=3")
-        # If body is "razdrez", then on_end_request is being called too early.
-        self.assertErrorPage(502, pattern=valerr)
-        # If this fails, then on_end_request isn't being called at all.
-        time.sleep(0.1)
-        self.getPage("/demo/ended/3")
-        self.assertBody("True")
-        
-        # If body is "razdrez", then on_end_request is being called too early.
-        if (cherrypy.server.protocol_version == "HTTP/1.0" or
-            getattr(cherrypy.server, "using_apache", False)):
-            self.getPage("/demo/errinstream?id=5")
-            # Because this error is raised after the response body has
-            # started, the status should not change to an error status.
-            self.assertStatus("200 OK")
-            self.assertBody("nonconfidential")
-        else:
-            # Because this error is raised after the response body has
-            # started, and because it's chunked output, an error is raised by
-            # the HTTP client when it encounters incomplete output.
-            self.assertRaises((ValueError, IncompleteRead), self.getPage,
-                              "/demo/errinstream?id=5")
-        # If this fails, then on_end_request isn't being called at all.
-        time.sleep(0.1)
-        self.getPage("/demo/ended/5")
-        self.assertBody("True")
-        
-        # Test the "__call__" technique (compile-time decorator).
-        self.getPage("/demo/restricted")
-        self.assertErrorPage(401)
-        
-        # Test compile-time decorator with kwargs from config.
-        self.getPage("/demo/userid")
-        self.assertBody("Welcome!")
-    
-    def testEndRequestOnDrop(self):
-        old_timeout = None
-        try:
-            httpserver = cherrypy.server.httpserver
-            old_timeout = httpserver.timeout
-        except (AttributeError, IndexError):
-            return self.skip()
-        
-        try:
-            httpserver.timeout = timeout
-            
-            # Test that on_end_request is called even if the client drops.
-            self.persistent = True
-            try:
-                conn = self.HTTP_CONN
-                conn.putrequest("GET", "/demo/stream?id=9", skip_host=True)
-                conn.putheader("Host", self.HOST)
-                conn.endheaders()
-                # Skip the rest of the request and close the conn. This will
-                # cause the server's active socket to error, which *should*
-                # result in the request being aborted, and request.close being
-                # called all the way up the stack (including WSGI middleware),
-                # eventually calling our on_end_request hook.
-            finally:
-                self.persistent = False
-            time.sleep(timeout * 2)
-            # Test that the on_end_request hook was called.
-            self.getPage("/demo/ended/9")
-            self.assertBody("True")
-        finally:
-            if old_timeout is not None:
-                httpserver.timeout = old_timeout
-    
-    def testGuaranteedHooks(self):
-        # The 'critical' on_start_resource hook is 'failsafe' (guaranteed
-        # to run even if there are failures in other on_start methods).
-        # This is NOT true of the other hooks.
-        # Here, we have set up a failure in NumerifyTool.numerify_map,
-        # but our 'critical' hook should run and set the error to 502.
-        self.getPage("/demo/err_in_onstart")
-        self.assertErrorPage(502)
-        self.assertInBody("AttributeError: 'str' object has no attribute 'items'")
-    
-    def testCombinedTools(self):
-        expectedResult = (u"Hello,world" + europoundUnicode).encode('utf-8')
-        zbuf = StringIO()
-        zfile = gzip.GzipFile(mode='wb', fileobj=zbuf, compresslevel=9)
-        zfile.write(expectedResult)
-        zfile.close()
-        
-        self.getPage("/euro", headers=[("Accept-Encoding", "gzip"),
-                                        ("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7")])
-        self.assertInBody(zbuf.getvalue()[:3])
-        
-        zbuf = StringIO()
-        zfile = gzip.GzipFile(mode='wb', fileobj=zbuf, compresslevel=6)
-        zfile.write(expectedResult)
-        zfile.close()
-        
-        self.getPage("/decorated_euro", headers=[("Accept-Encoding", "gzip")])
-        self.assertInBody(zbuf.getvalue()[:3])
-        
-        # This returns a different value because gzip's priority was
-        # lowered in conf, allowing the rotator to run after gzip.
-        # Of course, we don't want breakage in production apps,
-        # but it proves the priority was changed.
-        self.getPage("/decorated_euro/subpath",
-                     headers=[("Accept-Encoding", "gzip")])
-        self.assertInBody(''.join([chr((ord(x) + 3) % 256) for x in zbuf.getvalue()]))
-    
-    def testBareHooks(self):
-        content = "bit of a pain in me gulliver"
-        self.getPage("/pipe",
-                     headers=[("Content-Length", len(content)),
-                              ("Content-Type", "text/plain")],
-                     method="POST", body=content)
-        self.assertBody(content)
-    
-    def testHandlerWrapperTool(self):
-        self.getPage("/tarfile")
-        self.assertBody("I am a tarfile")
-    
-    def testToolWithConfig(self):
-        if not sys.version_info >= (2, 5):
-            return self.skip("skipped (Python 2.5+ only)")
-        
-        self.getPage('/tooldecs/blah')
-        self.assertHeader('Content-Type', 'application/data')
-    
-    def testWarnToolOn(self):
-        # get
-        try:
-            numon = cherrypy.tools.numerify.on
-        except AttributeError:
-            pass
-        else:
-            raise AssertionError("Tool.on did not error as it should have.")
-        
-        # set
-        try:
-            cherrypy.tools.numerify.on = True
-        except AttributeError:
-            pass
-        else:
-            raise AssertionError("Tool.on did not error as it should have.")
-
-
-
-if __name__ == '__main__':
-    helper.testmain()
-
--- a/bundled/cherrypy/cherrypy/test/test_tutorials.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,210 +0,0 @@
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import sys
-
-import cherrypy
-from cherrypy.test import helper
-
-
-def setup_server():
-    
-    conf = cherrypy.config.copy()
-    
-    def load_tut_module(name):
-        """Import or reload tutorial module as needed."""
-        cherrypy.config.reset()
-        cherrypy.config.update(conf)
-        
-        target = "cherrypy.tutorial." + name
-        if target in sys.modules:
-            module = reload(sys.modules[target])
-        else:
-            module = __import__(target, globals(), locals(), [''])
-        # The above import will probably mount a new app at "".
-        app = cherrypy.tree.apps[""]
-        
-        app.root.load_tut_module = load_tut_module
-        app.root.sessions = sessions
-        app.root.traceback_setting = traceback_setting
-        
-        test.sync_apps()
-    load_tut_module.exposed = True
-    
-    def sessions():
-        cherrypy.config.update({"tools.sessions.on": True})
-    sessions.exposed = True
-    
-    def traceback_setting():
-        return repr(cherrypy.request.show_tracebacks)
-    traceback_setting.exposed = True
-    
-    class Dummy:
-        pass
-    root = Dummy()
-    root.load_tut_module = load_tut_module
-    cherrypy.tree.mount(root)
-
-
-class TutorialTest(helper.CPWebCase):
-    
-    def test01HelloWorld(self):
-        self.getPage("/load_tut_module/tut01_helloworld")
-        self.getPage("/")
-        self.assertBody('Hello world!')
-    
-    def test02ExposeMethods(self):
-        self.getPage("/load_tut_module/tut02_expose_methods")
-        self.getPage("/showMessage")
-        self.assertBody('Hello world!')
-    
-    def test03GetAndPost(self):
-        self.getPage("/load_tut_module/tut03_get_and_post")
-        
-        # Try different GET queries
-        self.getPage("/greetUser?name=Bob")
-        self.assertBody("Hey Bob, what's up?")
-        
-        self.getPage("/greetUser")
-        self.assertBody('Please enter your name <a href="./">here</a>.')
-        
-        self.getPage("/greetUser?name=")
-        self.assertBody('No, really, enter your name <a href="./">here</a>.')
-        
-        # Try the same with POST
-        self.getPage("/greetUser", method="POST", body="name=Bob")
-        self.assertBody("Hey Bob, what's up?")
-        
-        self.getPage("/greetUser", method="POST", body="name=")
-        self.assertBody('No, really, enter your name <a href="./">here</a>.')
-    
-    def test04ComplexSite(self):
-        self.getPage("/load_tut_module/tut04_complex_site")
-        msg = '''
-            <p>Here are some extra useful links:</p>
-            
-            <ul>
-                <li><a href="http://del.icio.us">del.icio.us</a></li>
-                <li><a href="http://www.mornography.de">Hendrik's weblog</a></li>
-            </ul>
-            
-            <p>[<a href="../">Return to links page</a>]</p>'''
-        self.getPage("/links/extra/")
-        self.assertBody(msg)
-    
-    def test05DerivedObjects(self):
-        self.getPage("/load_tut_module/tut05_derived_objects")
-        msg = '''
-            <html>
-            <head>
-                <title>Another Page</title>
-            <head>
-            <body>
-            <h2>Another Page</h2>
-        
-            <p>
-            And this is the amazing second page!
-            </p>
-        
-            </body>
-            </html>
-        '''
-        self.getPage("/another/")
-        self.assertBody(msg)
-    
-    def test06DefaultMethod(self):
-        self.getPage("/load_tut_module/tut06_default_method")
-        self.getPage('/hendrik')
-        self.assertBody('Hendrik Mans, CherryPy co-developer & crazy German '
-                        '(<a href="./">back</a>)')
-    
-    def test07Sessions(self):
-        self.getPage("/load_tut_module/tut07_sessions")
-        self.getPage("/sessions")
-        
-        self.getPage('/')
-        self.assertBody("\n            During your current session, you've viewed this"
-                         "\n            page 1 times! Your life is a patio of fun!"
-                         "\n        ")
-        
-        self.getPage('/', self.cookies)
-        self.assertBody("\n            During your current session, you've viewed this"
-                         "\n            page 2 times! Your life is a patio of fun!"
-                         "\n        ")
-    
-    def test08GeneratorsAndYield(self):
-        self.getPage("/load_tut_module/tut08_generators_and_yield")
-        self.getPage('/')
-        self.assertBody('<html><body><h2>Generators rule!</h2>'
-                         '<h3>List of users:</h3>'
-                         'Remi<br/>Carlos<br/>Hendrik<br/>Lorenzo Lamas<br/>'
-                         '</body></html>')
-    
-    def test09Files(self):
-        self.getPage("/load_tut_module/tut09_files")
-        
-        # Test upload
-        filesize = 5
-        h = [("Content-type", "multipart/form-data; boundary=x"),
-             ("Content-Length", str(105 + filesize))]
-        b = '--x\n' + \
-            'Content-Disposition: form-data; name="myFile"; filename="hello.txt"\r\n' + \
-            'Content-Type: text/plain\r\n' + \
-            '\r\n' + \
-            'a' * filesize + '\n' + \
-            '--x--\n'
-        self.getPage('/upload', h, "POST", b)
-        self.assertBody('''<html>
-        <body>
-            myFile length: %d<br />
-            myFile filename: hello.txt<br />
-            myFile mime-type: text/plain
-        </body>
-        </html>''' % filesize)
-    
-        # Test download
-        self.getPage('/download')
-        self.assertStatus("200 OK")
-        self.assertHeader("Content-Type", "application/x-download")
-        self.assertHeader("Content-Disposition",
-                          # Make sure the filename is quoted.
-                          'attachment; filename="pdf_file.pdf"')
-        self.assertEqual(len(self.body), 85698)
-    
-    def test10HTTPErrors(self):
-        self.getPage("/load_tut_module/tut10_http_errors")
-        
-        self.getPage("/")
-        self.assertInBody("""<a href="toggleTracebacks">""")
-        self.assertInBody("""<a href="/doesNotExist">""")
-        self.assertInBody("""<a href="/error?code=403">""")
-        self.assertInBody("""<a href="/error?code=500">""")
-        self.assertInBody("""<a href="/messageArg">""")
-        
-        self.getPage("/traceback_setting")
-        setting = self.body
-        self.getPage("/toggleTracebacks")
-        self.assertStatus((302, 303))
-        self.getPage("/traceback_setting")
-        self.assertBody(str(not eval(setting)))
-        
-        self.getPage("/error?code=500")
-        self.assertStatus(500)
-        self.assertInBody("The server encountered an unexpected condition "
-                          "which prevented it from fulfilling the request.")
-        
-        self.getPage("/error?code=403")
-        self.assertStatus(403)
-        self.assertInBody("<h2>You can't do that!</h2>")
-        
-        self.getPage("/messageArg")
-        self.assertStatus(500)
-        self.assertInBody("If you construct an HTTPError with a 'message'")
-
-
-if __name__ == "__main__":
-    helper.testmain({
-        'server.socket_host': '127.0.0.1',
-        'server.socket_port': 8080,
-        'server.thread_pool': 10,
-        })
--- a/bundled/cherrypy/cherrypy/test/test_virtualhost.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import os
-curdir = os.path.join(os.getcwd(), os.path.dirname(__file__))
-
-import cherrypy
-
-def setup_server():
-    class Root:
-        def index(self):
-            return "Hello, world"
-        index.exposed = True
-        
-        def dom4(self):
-            return "Under construction"
-        dom4.exposed = True
-        
-        def method(self, value):
-            return "You sent %s" % repr(value)
-        method.exposed = True
-    
-    class VHost:
-        def __init__(self, sitename):
-            self.sitename = sitename
-        
-        def index(self):
-            return "Welcome to %s" % self.sitename
-        index.exposed = True
-        
-        def vmethod(self, value):
-            return "You sent %s" % repr(value)
-        vmethod.exposed = True
-        
-        def url(self):
-            return cherrypy.url("nextpage")
-        url.exposed = True
-        
-        # Test static as a handler (section must NOT include vhost prefix)
-        static = cherrypy.tools.staticdir.handler(section='/static', dir=curdir)
-    
-    root = Root()
-    root.mydom2 = VHost("Domain 2")
-    root.mydom3 = VHost("Domain 3")
-    hostmap = {'www.mydom2.com': '/mydom2',
-               'www.mydom3.com': '/mydom3',
-               'www.mydom4.com': '/dom4',
-               }
-    cherrypy.tree.mount(root, config={
-        '/': {'request.dispatch': cherrypy.dispatch.VirtualHost(**hostmap)},
-        # Test static in config (section must include vhost prefix)
-        '/mydom2/static2': {'tools.staticdir.on': True,
-                            'tools.staticdir.root': curdir,
-                            'tools.staticdir.dir': 'static',
-                            'tools.staticdir.index': 'index.html',
-                            },
-        })
-
-
-from cherrypy.test import helper
-
-class VirtualHostTest(helper.CPWebCase):
-    
-    def testVirtualHost(self):
-        self.getPage("/", [('Host', 'www.mydom1.com')])
-        self.assertBody('Hello, world')
-        self.getPage("/mydom2/", [('Host', 'www.mydom1.com')])
-        self.assertBody('Welcome to Domain 2')
-        
-        self.getPage("/", [('Host', 'www.mydom2.com')])
-        self.assertBody('Welcome to Domain 2')
-        self.getPage("/", [('Host', 'www.mydom3.com')])
-        self.assertBody('Welcome to Domain 3')
-        self.getPage("/", [('Host', 'www.mydom4.com')])
-        self.assertBody('Under construction')
-        
-        # Test GET, POST, and positional params
-        self.getPage("/method?value=root")
-        self.assertBody("You sent u'root'")
-        self.getPage("/vmethod?value=dom2+GET", [('Host', 'www.mydom2.com')])
-        self.assertBody("You sent u'dom2 GET'")
-        self.getPage("/vmethod", [('Host', 'www.mydom3.com')], method="POST",
-                     body="value=dom3+POST")
-        self.assertBody("You sent u'dom3 POST'")
-        self.getPage("/vmethod/pos", [('Host', 'www.mydom3.com')])
-        self.assertBody("You sent 'pos'")
-        
-        # Test that cherrypy.url uses the browser url, not the virtual url
-        self.getPage("/url", [('Host', 'www.mydom2.com')])
-        self.assertBody("%s://www.mydom2.com/nextpage" % self.scheme)
-    
-    def test_VHost_plus_Static(self):
-        # Test static as a handler
-        self.getPage("/static/style.css", [('Host', 'www.mydom2.com')])
-        self.assertStatus('200 OK')
-        self.assertHeader('Content-Type', 'text/css;charset=utf-8')
-        
-        # Test static in config
-        self.getPage("/static2/dirback.jpg", [('Host', 'www.mydom2.com')])
-        self.assertStatus('200 OK')
-        self.assertHeader('Content-Type', 'image/jpeg')
-        
-        # Test static config with "index" arg
-        self.getPage("/static2/", [('Host', 'www.mydom2.com')])
-        self.assertStatus('200 OK')
-        self.assertBody('Hello, world\r\n')
-        # Since tools.trailing_slash is on by default, this should redirect
-        self.getPage("/static2", [('Host', 'www.mydom2.com')])
-        self.assertStatus(301)
-
-
-if __name__ == "__main__":
-    helper.testmain()
--- a/bundled/cherrypy/cherrypy/test/test_wsgi_ns.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,87 +0,0 @@
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import cherrypy
-
-
-def setup_server():
-    
-    class WSGIResponse(object):
-        
-        def __init__(self, appresults):
-            self.appresults = appresults
-            self.iter = iter(appresults)
-        
-        def __iter__(self):
-            return self
-        
-        def next(self):
-            return self.iter.next()
-        
-        def close(self):
-            if hasattr(self.appresults, "close"):
-                self.appresults.close()
-    
-    
-    class ChangeCase(object):
-        
-        def __init__(self, app, to=None):
-            self.app = app
-            self.to = to
-        
-        def __call__(self, environ, start_response):
-            res = self.app(environ, start_response)
-            class CaseResults(WSGIResponse):
-                def next(this):
-                    return getattr(this.iter.next(), self.to)()
-            return CaseResults(res)
-    
-    class Replacer(object):
-        
-        def __init__(self, app, map={}):
-            self.app = app
-            self.map = map
-        
-        def __call__(self, environ, start_response):
-            res = self.app(environ, start_response)
-            class ReplaceResults(WSGIResponse):
-                def next(this):
-                    line = this.iter.next()
-                    for k, v in self.map.iteritems():
-                        line = line.replace(k, v)
-                    return line
-            return ReplaceResults(res)
-    
-    class Root(object):
-        
-        def index(self):
-            return "HellO WoRlD!"
-        index.exposed = True
-    
-    
-    root_conf = {'wsgi.pipeline': [('replace', Replacer)],
-                 'wsgi.replace.map': {'L': 'X', 'l': 'r'},
-                 }
-    
-    app = cherrypy.Application(Root())
-    app.wsgiapp.pipeline.append(('changecase', ChangeCase))
-    app.wsgiapp.config['changecase'] = {'to': 'upper'}
-    cherrypy.tree.mount(app, config={'/': root_conf})
-
-
-from cherrypy.test import helper
-
-
-class WSGI_Namespace_Test(helper.CPWebCase):
-    
-    def test_pipeline(self):
-        if not cherrypy.server.httpserver:
-            return self.skip()
-        
-        self.getPage("/")
-        # If body is "HEXXO WORXD!", the middleware was applied out of order.
-        self.assertBody("HERRO WORRD!")
-
-if __name__ == '__main__':
-    helper.testmain()
-
--- a/bundled/cherrypy/cherrypy/test/test_wsgi_vhost.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-from cherrypy.test import test
-test.prefer_parent_path()
-
-import cherrypy
-
-
-def setup_server():
-    
-    class ClassOfRoot(object):
-        
-        def __init__(self, name):
-            self.name = name
-        
-        def index(self):
-            return "Welcome to the %s website!" % self.name
-        index.exposed = True
-    
-    
-    default = cherrypy.Application(None)
-    
-    domains = {}
-    for year in range(1997, 2008):
-        app = cherrypy.Application(ClassOfRoot('Class of %s' % year))
-        domains['www.classof%s.example' % year] = app
-    
-    cherrypy.tree.graft(cherrypy._cpwsgi.VirtualHost(default, domains))
-
-
-from cherrypy.test import helper
-
-
-class WSGI_VirtualHost_Test(helper.CPWebCase):
-    
-    def test_welcome(self):
-        if not cherrypy.server.using_wsgi:
-            return self.skip("skipped (not using WSGI)... ")
-        
-        for year in range(1997, 2008):
-            self.getPage("/", headers=[('Host', 'www.classof%s.example' % year)])
-            self.assertBody("Welcome to the Class of %s website!" % year)
-
-
-if __name__ == '__main__':
-    helper.testmain()
-
--- a/bundled/cherrypy/cherrypy/test/test_wsgiapps.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-from cherrypy.test import test
-test.prefer_parent_path()
-
-
-def setup_server():
-    import os
-    curdir = os.path.join(os.getcwd(), os.path.dirname(__file__))
-    
-    import cherrypy
-    
-    def test_app(environ, start_response):
-        status = '200 OK'
-        response_headers = [('Content-type', 'text/plain')]
-        start_response(status, response_headers)
-        output = ['Hello, world!\n',
-                  'This is a wsgi app running within CherryPy!\n\n']
-        keys = list(environ.keys())
-        keys.sort()
-        for k in keys:
-            output.append('%s: %s\n' % (k,environ[k]))
-        return output
-    
-    def test_empty_string_app(environ, start_response):
-        status = '200 OK'
-        response_headers = [('Content-type', 'text/plain')]
-        start_response(status, response_headers)
-        return ['Hello', '', ' ', '', 'world']
-    
-    
-    class WSGIResponse(object):
-        
-        def __init__(self, appresults):
-            self.appresults = appresults
-            self.iter = iter(appresults)
-        
-        def __iter__(self):
-            return self
-        
-        def next(self):
-            return self.iter.next()
-        
-        def close(self):
-            if hasattr(self.appresults, "close"):
-                self.appresults.close()
-    
-    
-    class ReversingMiddleware(object):
-        
-        def __init__(self, app):
-            self.app = app
-        
-        def __call__(self, environ, start_response):
-            results = app(environ, start_response)
-            class Reverser(WSGIResponse):
-                def next(this):
-                    line = list(this.iter.next())
-                    line.reverse()
-                    return "".join(line)
-            return Reverser(results)
-    
-    class Root:
-        def index(self):
-            return "I'm a regular CherryPy page handler!"
-        index.exposed = True
-    
-    
-    cherrypy.tree.mount(Root())
-    
-    cherrypy.tree.graft(test_app, '/hosted/app1')
-    cherrypy.tree.graft(test_empty_string_app, '/hosted/app3')
-    
-    # Set script_name explicitly to None to signal CP that it should
-    # be pulled from the WSGI environ each time.
-    app = cherrypy.Application(Root(), script_name=None)
-    cherrypy.tree.graft(ReversingMiddleware(app), '/hosted/app2')
-
-from cherrypy.test import helper
-
-
-class WSGIGraftTests(helper.CPWebCase):
-    
-    wsgi_output = '''Hello, world!
-This is a wsgi app running within CherryPy!'''
-
-    def test_01_standard_app(self):
-        self.getPage("/")
-        self.assertBody("I'm a regular CherryPy page handler!")
-    
-    def test_04_pure_wsgi(self):
-        import cherrypy
-        if not cherrypy.server.using_wsgi:
-            return self.skip("skipped (not using WSGI)... ")
-        self.getPage("/hosted/app1")
-        self.assertHeader("Content-Type", "text/plain")
-        self.assertInBody(self.wsgi_output)
-
-    def test_05_wrapped_cp_app(self):
-        import cherrypy
-        if not cherrypy.server.using_wsgi:
-            return self.skip("skipped (not using WSGI)... ")
-        self.getPage("/hosted/app2/")
-        body = list("I'm a regular CherryPy page handler!")
-        body.reverse()
-        body = "".join(body)
-        self.assertInBody(body)
-
-    def test_06_empty_string_app(self):
-        import cherrypy
-        if not cherrypy.server.using_wsgi:
-            return self.skip("skipped (not using WSGI)... ")
-        self.getPage("/hosted/app3")
-        self.assertHeader("Content-Type", "text/plain")
-        self.assertInBody('Hello world')
-
-if __name__ == '__main__':
-    helper.testmain()
-
--- a/bundled/cherrypy/cherrypy/test/test_xmlrpc.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,175 +0,0 @@
-from cherrypy.test import test
-test.prefer_parent_path()
-import xmlrpclib
-
-import cherrypy
-
-
-def setup_server():
-    from cherrypy import _cptools
-    
-    class Root:
-        def index(self):
-            return "I'm a standard index!"
-        index.exposed = True
-
-
-    class XmlRpc(_cptools.XMLRPCController):
-        
-        def foo(self):
-            return "Hello world!"
-        foo.exposed = True
-        
-        def return_single_item_list(self):
-            return [42]
-        return_single_item_list.exposed = True
-        
-        def return_string(self):
-            return "here is a string"
-        return_string.exposed = True
-        
-        def return_tuple(self):
-            return ('here', 'is', 1, 'tuple')
-        return_tuple.exposed = True
-        
-        def return_dict(self):
-            return dict(a=1, b=2, c=3)
-        return_dict.exposed = True
-        
-        def return_composite(self):
-            return dict(a=1,z=26), 'hi', ['welcome', 'friend']
-        return_composite.exposed = True
-
-        def return_int(self):
-            return 42
-        return_int.exposed = True
-
-        def return_float(self):
-            return 3.14
-        return_float.exposed = True
-
-        def return_datetime(self):
-            return xmlrpclib.DateTime((2003, 10, 7, 8, 1, 0, 1, 280, -1))
-        return_datetime.exposed = True
-
-        def return_boolean(self):
-            return True
-        return_boolean.exposed = True
-
-        def test_argument_passing(self, num):
-            return num * 2
-        test_argument_passing.exposed = True
-
-        def test_returning_Fault(self):
-            return xmlrpclib.Fault(1, "custom Fault response")
-        test_returning_Fault.exposed = True
-
-    root = Root()
-    root.xmlrpc = XmlRpc()
-    cherrypy.tree.mount(root, config={'/': {
-        'request.dispatch': cherrypy.dispatch.XMLRPCDispatcher(),
-        'tools.xmlrpc.allow_none': 0,
-        }})
-
-
-class HTTPSTransport(xmlrpclib.SafeTransport):
-    """Subclass of SafeTransport to fix sock.recv errors (by using file)."""
-    
-    def request(self, host, handler, request_body, verbose=0):
-        # issue XML-RPC request
-        h = self.make_connection(host)
-        if verbose:
-            h.set_debuglevel(1)
-        
-        self.send_request(h, handler, request_body)
-        self.send_host(h, host)
-        self.send_user_agent(h)
-        self.send_content(h, request_body)
-        
-        errcode, errmsg, headers = h.getreply()
-        if errcode != 200:
-            raise xmlrpclib.ProtocolError(host + handler, errcode, errmsg,
-                                          headers)
-        
-        self.verbose = verbose
-        
-        # Here's where we differ from the superclass. It says:
-        # try:
-        #     sock = h._conn.sock
-        # except AttributeError:
-        #     sock = None
-        # return self._parse_response(h.getfile(), sock)
-        
-        return self.parse_response(h.getfile())
-
-
-from cherrypy.test import helper
-
-class XmlRpcTest(helper.CPWebCase):
-    def testXmlRpc(self):
-        
-        # load the appropriate xmlrpc proxy
-        scheme = "http"
-        try:
-            scheme = self.harness.scheme
-        except AttributeError:
-            pass
-        
-        if scheme == "https":
-            url = 'https://%s:%s/xmlrpc/' % (self.interface(), self.PORT)
-            proxy = xmlrpclib.ServerProxy(url, transport=HTTPSTransport())
-        else:
-            url = 'http://%s:%s/xmlrpc/' % (self.interface(), self.PORT)
-            proxy = xmlrpclib.ServerProxy(url)
-        
-        # begin the tests ...
-        self.getPage("/xmlrpc/foo")
-        self.assertBody("Hello world!")
-        
-        self.assertEqual(proxy.return_single_item_list(), [42])
-        self.assertNotEqual(proxy.return_single_item_list(), 'one bazillion')
-        self.assertEqual(proxy.return_string(), "here is a string")
-        self.assertEqual(proxy.return_tuple(), list(('here', 'is', 1, 'tuple')))
-        self.assertEqual(proxy.return_dict(), {'a': 1, 'c': 3, 'b': 2})
-        self.assertEqual(proxy.return_composite(),
-                         [{'a': 1, 'z': 26}, 'hi', ['welcome', 'friend']])
-        self.assertEqual(proxy.return_int(), 42)
-        self.assertEqual(proxy.return_float(), 3.14)
-        self.assertEqual(proxy.return_datetime(),
-                         xmlrpclib.DateTime((2003, 10, 7, 8, 1, 0, 1, 280, -1)))
-        self.assertEqual(proxy.return_boolean(), True)
-        self.assertEqual(proxy.test_argument_passing(22), 22 * 2)
-        
-        # Test an error in the page handler (should raise an xmlrpclib.Fault)
-        try:
-            proxy.test_argument_passing({})
-        except Exception, x:
-            self.assertEqual(x.__class__, xmlrpclib.Fault)
-            self.assertEqual(x.faultString, ("unsupported operand type(s) "
-                                             "for *: 'dict' and 'int'"))
-        else:
-            self.fail("Expected xmlrpclib.Fault")
-        
-        # http://www.cherrypy.org/ticket/533
-        # if a method is not found, an xmlrpclib.Fault should be raised
-        try:
-            proxy.non_method()
-        except Exception, x:
-            self.assertEqual(x.__class__, xmlrpclib.Fault)
-            self.assertEqual(x.faultString, 'method "non_method" is not supported')
-        else:
-            self.fail("Expected xmlrpclib.Fault")
-        
-        # Test returning a Fault from the page handler.
-        try:
-            proxy.test_returning_Fault()
-        except Exception, x:
-            self.assertEqual(x.__class__, xmlrpclib.Fault)
-            self.assertEqual(x.faultString, ("custom Fault response"))
-        else:
-            self.fail("Expected xmlrpclib.Fault")
-
-
-if __name__ == '__main__':
-    helper.testmain()
-
--- a/bundled/cherrypy/cherrypy/test/webtest.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,597 +0,0 @@
-"""Extensions to unittest for web frameworks.
-
-Use the WebCase.getPage method to request a page from your HTTP server.
-
-Framework Integration
-=====================
-
-If you have control over your server process, you can handle errors
-in the server-side of the HTTP conversation a bit better. You must run
-both the client (your WebCase tests) and the server in the same process
-(but in separate threads, obviously).
-
-When an error occurs in the framework, call server_error. It will print
-the traceback to stdout, and keep any assertions you have from running
-(the assumption is that, if the server errors, the page output will not
-be of further significance to your tests).
-"""
-
-from httplib import HTTPConnection, HTTPSConnection
-import os
-import pprint
-import re
-import socket
-import sys
-import time
-import traceback
-import types
-
-from unittest import *
-from unittest import _TextTestResult
-
-
-
-def interface(host):
-    """Return an IP address for a client connection given the server host.
-    
-    If the server is listening on '0.0.0.0' (INADDR_ANY)
-    or '::' (IN6ADDR_ANY), this will return the proper localhost."""
-    if host == '0.0.0.0':
-        # INADDR_ANY, which should respond on localhost.
-        return "127.0.0.1"
-    if host == '::':
-        # IN6ADDR_ANY, which should respond on localhost.
-        return "::1"
-    return host
-
-
-class TerseTestResult(_TextTestResult):
-    
-    def printErrors(self):
-        # Overridden to avoid unnecessary empty line
-        if self.errors or self.failures:
-            if self.dots or self.showAll:
-                self.stream.writeln()
-            self.printErrorList('ERROR', self.errors)
-            self.printErrorList('FAIL', self.failures)
-
-
-class TerseTestRunner(TextTestRunner):
-    """A test runner class that displays results in textual form."""
-    
-    def _makeResult(self):
-        return TerseTestResult(self.stream, self.descriptions, self.verbosity)
-    
-    def run(self, test):
-        "Run the given test case or test suite."
-        # Overridden to remove unnecessary empty lines and separators
-        result = self._makeResult()
-        test(result)
-        result.printErrors()
-        if not result.wasSuccessful():
-            self.stream.write("FAILED (")
-            failed, errored = map(len, (result.failures, result.errors))
-            if failed:
-                self.stream.write("failures=%d" % failed)
-            if errored:
-                if failed: self.stream.write(", ")
-                self.stream.write("errors=%d" % errored)
-            self.stream.writeln(")")
-        return result
-
-
-class ReloadingTestLoader(TestLoader):
-    
-    def loadTestsFromName(self, name, module=None):
-        """Return a suite of all tests cases given a string specifier.
-
-        The name may resolve either to a module, a test case class, a
-        test method within a test case class, or a callable object which
-        returns a TestCase or TestSuite instance.
-
-        The method optionally resolves the names relative to a given module.
-        """
-        parts = name.split('.')
-        unused_parts = []
-        if module is None:
-            if not parts:
-                raise ValueError("incomplete test name: %s" % name)
-            else:
-                parts_copy = parts[:]
-                while parts_copy:
-                    target = ".".join(parts_copy)
-                    if target in sys.modules:
-                        module = reload(sys.modules[target])
-                        parts = unused_parts
-                        break
-                    else:
-                        try:
-                            module = __import__(target)
-                            parts = unused_parts
-                            break
-                        except ImportError:
-                            unused_parts.insert(0,parts_copy[-1])
-                            del parts_copy[-1]
-                            if not parts_copy:
-                                raise
-                parts = parts[1:]
-        obj = module
-        for part in parts:
-            obj = getattr(obj, part)
-        
-        if type(obj) == types.ModuleType:
-            return self.loadTestsFromModule(obj)
-        elif (isinstance(obj, (type, types.ClassType)) and
-              issubclass(obj, TestCase)):
-            return self.loadTestsFromTestCase(obj)
-        elif type(obj) == types.UnboundMethodType:
-            return obj.im_class(obj.__name__)
-        elif callable(obj):
-            test = obj()
-            if not isinstance(test, TestCase) and \
-               not isinstance(test, TestSuite):
-                raise ValueError("calling %s returned %s, "
-                                 "not a test" % (obj,test))
-            return test
-        else:
-            raise ValueError("do not know how to make test from: %s" % obj)
-
-
-try:
-    # On Windows, msvcrt.getch reads a single char without output.
-    import msvcrt
-    def getchar():
-        return msvcrt.getch()
-except ImportError:
-    # Unix getchr
-    import tty, termios
-    def getchar():
-        fd = sys.stdin.fileno()
-        old_settings = termios.tcgetattr(fd)
-        try:
-            tty.setraw(sys.stdin.fileno())
-            ch = sys.stdin.read(1)
-        finally:
-            termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
-        return ch
-
-
-class WebCase(TestCase):
-    HOST = "127.0.0.1"
-    PORT = 8000
-    HTTP_CONN = HTTPConnection
-    PROTOCOL = "HTTP/1.1"
-    
-    scheme = "http"
-    url = None
-    
-    status = None
-    headers = None
-    body = None
-    time = None
-    
-    def get_conn(self, auto_open=False):
-        """Return a connection to our HTTP server."""
-        if self.scheme == "https":
-            cls = HTTPSConnection
-        else:
-            cls = HTTPConnection
-        conn = cls(self.interface(), self.PORT)
-        # Automatically re-connect?
-        conn.auto_open = auto_open
-        conn.connect()
-        return conn
-    
-    def set_persistent(self, on=True, auto_open=False):
-        """Make our HTTP_CONN persistent (or not).
-        
-        If the 'on' argument is True (the default), then self.HTTP_CONN
-        will be set to an instance of HTTPConnection (or HTTPS
-        if self.scheme is "https"). This will then persist across requests.
-        
-        We only allow for a single open connection, so if you call this
-        and we currently have an open connection, it will be closed.
-        """
-        try:
-            self.HTTP_CONN.close()
-        except (TypeError, AttributeError):
-            pass
-        
-        if on:
-            self.HTTP_CONN = self.get_conn(auto_open=auto_open)
-        else:
-            if self.scheme == "https":
-                self.HTTP_CONN = HTTPSConnection
-            else:
-                self.HTTP_CONN = HTTPConnection
-    
-    def _get_persistent(self):
-        return hasattr(self.HTTP_CONN, "__class__")
-    def _set_persistent(self, on):
-        self.set_persistent(on)
-    persistent = property(_get_persistent, _set_persistent)
-    
-    def interface(self):
-        """Return an IP address for a client connection.
-        
-        If the server is listening on '0.0.0.0' (INADDR_ANY)
-        or '::' (IN6ADDR_ANY), this will return the proper localhost."""
-        return interface(self.HOST)
-    
-    def getPage(self, url, headers=None, method="GET", body=None, protocol=None):
-        """Open the url with debugging support. Return status, headers, body."""
-        ServerError.on = False
-        
-        self.url = url
-        self.time = None
-        start = time.time()
-        result = openURL(url, headers, method, body, self.HOST, self.PORT,
-                         self.HTTP_CONN, protocol or self.PROTOCOL)
-        self.time = time.time() - start
-        self.status, self.headers, self.body = result
-        
-        # Build a list of request cookies from the previous response cookies.
-        self.cookies = [('Cookie', v) for k, v in self.headers
-                        if k.lower() == 'set-cookie']
-        
-        if ServerError.on:
-            raise ServerError()
-        return result
-    
-    interactive = True
-    console_height = 30
-    
-    def _handlewebError(self, msg):
-        import cherrypy
-        print("")
-        print("    ERROR: %s" % msg)
-        
-        if not self.interactive:
-            raise self.failureException(msg)
-        
-        p = "    Show: [B]ody [H]eaders [S]tatus [U]RL; [I]gnore, [R]aise, or sys.e[X]it >> "
-        print p,
-        # ARGH!
-        sys.stdout.flush()
-        while True:
-            i = getchar().upper()
-            if i not in "BHSUIRX":
-                continue
-            print(i.upper())  # Also prints new line
-            if i == "B":
-                for x, line in enumerate(self.body.splitlines()):
-                    if (x + 1) % self.console_height == 0:
-                        # The \r and comma should make the next line overwrite
-                        print "<-- More -->\r",
-                        m = getchar().lower()
-                        # Erase our "More" prompt
-                        print "            \r",
-                        if m == "q":
-                            break
-                    print(line)
-            elif i == "H":
-                pprint.pprint(self.headers)
-            elif i == "S":
-                print(self.status)
-            elif i == "U":
-                print(self.url)
-            elif i == "I":
-                # return without raising the normal exception
-                return
-            elif i == "R":
-                raise self.failureException(msg)
-            elif i == "X":
-                self.exit()
-            print p,
-            # ARGH
-            sys.stdout.flush()    
-    def exit(self):
-        sys.exit()
-    
-    if sys.version_info >= (2, 5):
-        def __call__(self, result=None):
-            if result is None:
-                result = self.defaultTestResult()
-            result.startTest(self)
-            testMethod = getattr(self, self._testMethodName)
-            try:
-                try:
-                    self.setUp()
-                except (KeyboardInterrupt, SystemExit):
-                    raise
-                except:
-                    result.addError(self, self._exc_info())
-                    return
-                
-                ok = 0
-                try:
-                    testMethod()
-                    ok = 1
-                except self.failureException:
-                    result.addFailure(self, self._exc_info())
-                except (KeyboardInterrupt, SystemExit):
-                    raise
-                except:
-                    result.addError(self, self._exc_info())
-                
-                try:
-                    self.tearDown()
-                except (KeyboardInterrupt, SystemExit):
-                    raise
-                except:
-                    result.addError(self, self._exc_info())
-                    ok = 0
-                if ok:
-                    result.addSuccess(self)
-            finally:
-                result.stopTest(self)
-    else:
-        def __call__(self, result=None):
-            if result is None:
-                result = self.defaultTestResult()
-            result.startTest(self)
-            testMethod = getattr(self, self._TestCase__testMethodName)
-            try:
-                try:
-                    self.setUp()
-                except (KeyboardInterrupt, SystemExit):
-                    raise
-                except:
-                    result.addError(self, self._TestCase__exc_info())
-                    return
-                
-                ok = 0
-                try:
-                    testMethod()
-                    ok = 1
-                except self.failureException:
-                    result.addFailure(self, self._TestCase__exc_info())
-                except (KeyboardInterrupt, SystemExit):
-                    raise
-                except:
-                    result.addError(self, self._TestCase__exc_info())
-                
-                try:
-                    self.tearDown()
-                except (KeyboardInterrupt, SystemExit):
-                    raise
-                except:
-                    result.addError(self, self._TestCase__exc_info())
-                    ok = 0
-                if ok:
-                    result.addSuccess(self)
-            finally:
-                result.stopTest(self)
-    
-    def assertStatus(self, status, msg=None):
-        """Fail if self.status != status."""
-        if isinstance(status, basestring):
-            if not self.status == status:
-                if msg is None:
-                    msg = 'Status (%r) != %r' % (self.status, status)
-                self._handlewebError(msg)
-        elif isinstance(status, int):
-            code = int(self.status[:3])
-            if code != status:
-                if msg is None:
-                    msg = 'Status (%r) != %r' % (self.status, status)
-                self._handlewebError(msg)
-        else:
-            # status is a tuple or list.
-            match = False
-            for s in status:
-                if isinstance(s, basestring):
-                    if self.status == s:
-                        match = True
-                        break
-                elif int(self.status[:3]) == s:
-                    match = True
-                    break
-            if not match:
-                if msg is None:
-                    msg = 'Status (%r) not in %r' % (self.status, status)
-                self._handlewebError(msg)
-    
-    def assertHeader(self, key, value=None, msg=None):
-        """Fail if (key, [value]) not in self.headers."""
-        lowkey = key.lower()
-        for k, v in self.headers:
-            if k.lower() == lowkey:
-                if value is None or str(value) == v:
-                    return v
-        
-        if msg is None:
-            if value is None:
-                msg = '%r not in headers' % key
-            else:
-                msg = '%r:%r not in headers' % (key, value)
-        self._handlewebError(msg)
-    
-    def assertHeaderItemValue(self, key, value, msg=None):
-        """Fail if the header does not contain the specified value"""
-        actual_value = self.assertHeader(key, msg=msg)
-        header_values = map(str.strip, actual_value.split(','))
-        if value in header_values:
-            return value
-        
-        if msg is None:
-            msg = "%r not in %r" % (value, header_values)
-        self._handlewebError(msg)
-
-    def assertNoHeader(self, key, msg=None):
-        """Fail if key in self.headers."""
-        lowkey = key.lower()
-        matches = [k for k, v in self.headers if k.lower() == lowkey]
-        if matches:
-            if msg is None:
-                msg = '%r in headers' % key
-            self._handlewebError(msg)
-    
-    def assertBody(self, value, msg=None):
-        """Fail if value != self.body."""
-        if value != self.body:
-            if msg is None:
-                msg = 'expected body:\n%r\n\nactual body:\n%r' % (value, self.body)
-            self._handlewebError(msg)
-    
-    def assertInBody(self, value, msg=None):
-        """Fail if value not in self.body."""
-        if value not in self.body:
-            if msg is None:
-                msg = '%r not in body: %s' % (value, self.body)
-            self._handlewebError(msg)
-    
-    def assertNotInBody(self, value, msg=None):
-        """Fail if value in self.body."""
-        if value in self.body:
-            if msg is None:
-                msg = '%r found in body' % value
-            self._handlewebError(msg)
-    
-    def assertMatchesBody(self, pattern, msg=None, flags=0):
-        """Fail if value (a regex pattern) is not in self.body."""
-        if re.search(pattern, self.body, flags) is None:
-            if msg is None:
-                msg = 'No match for %r in body' % pattern
-            self._handlewebError(msg)
-
-
-methods_with_bodies = ("POST", "PUT")
-
-def cleanHeaders(headers, method, body, host, port):
-    """Return request headers, with required headers added (if missing)."""
-    if headers is None:
-        headers = []
-    
-    # Add the required Host request header if not present.
-    # [This specifies the host:port of the server, not the client.]
-    found = False
-    for k, v in headers:
-        if k.lower() == 'host':
-            found = True
-            break
-    if not found:
-        if port == 80:
-            headers.append(("Host", host))
-        else:
-            headers.append(("Host", "%s:%s" % (host, port)))
-    
-    if method in methods_with_bodies:
-        # Stick in default type and length headers if not present
-        found = False
-        for k, v in headers:
-            if k.lower() == 'content-type':
-                found = True
-                break
-        if not found:
-            headers.append(("Content-Type", "application/x-www-form-urlencoded"))
-            headers.append(("Content-Length", str(len(body or ""))))
-    
-    return headers
-
-
-def shb(response):
-    """Return status, headers, body the way we like from a response."""
-    h = []
-    key, value = None, None
-    for line in response.msg.headers:
-        if line:
-            if line[0] in " \t":
-                value += line.strip()
-            else:
-                if key and value:
-                    h.append((key, value))
-                key, value = line.split(":", 1)
-                key = key.strip()
-                value = value.strip()
-    if key and value:
-        h.append((key, value))
-    
-    return "%s %s" % (response.status, response.reason), h, response.read()
-
-
-def openURL(url, headers=None, method="GET", body=None,
-            host="127.0.0.1", port=8000, http_conn=HTTPConnection,
-            protocol="HTTP/1.1"):
-    """Open the given HTTP resource and return status, headers, and body."""
-    
-    headers = cleanHeaders(headers, method, body, host, port)
-    
-    # Trying 10 times is simply in case of socket errors.
-    # Normal case--it should run once.
-    for trial in range(10):
-        try:
-            # Allow http_conn to be a class or an instance
-            if hasattr(http_conn, "host"):
-                conn = http_conn
-            else:
-                conn = http_conn(interface(host), port)
-
-            conn._http_vsn_str = protocol
-            conn._http_vsn = int("".join([x for x in protocol if x.isdigit()]))
-            
-            # skip_accept_encoding argument added in python version 2.4
-            if sys.version_info < (2, 4):
-                def putheader(self, header, value):
-                    if header == 'Accept-Encoding' and value == 'identity':
-                        return
-                    self.__class__.putheader(self, header, value)
-                import new
-                conn.putheader = new.instancemethod(putheader, conn, conn.__class__)
-                conn.putrequest(method.upper(), url, skip_host=True)
-            else:
-                conn.putrequest(method.upper(), url, skip_host=True,
-                                skip_accept_encoding=True)
-            
-            for key, value in headers:
-                conn.putheader(key, value)
-            conn.endheaders()
-            
-            if body is not None:
-                conn.send(body)
-            
-            # Handle response
-            response = conn.getresponse()
-            
-            s, h, b = shb(response)
-            
-            if not hasattr(http_conn, "host"):
-                # We made our own conn instance. Close it.
-                conn.close()
-            
-            return s, h, b
-        except socket.error:
-            time.sleep(0.5)
-    raise
-
-
-# Add any exceptions which your web framework handles
-# normally (that you don't want server_error to trap).
-ignored_exceptions = []
-
-# You'll want set this to True when you can't guarantee
-# that each response will immediately follow each request;
-# for example, when handling requests via multiple threads.
-ignore_all = False
-
-class ServerError(Exception):
-    on = False
-
-
-def server_error(exc=None):
-    """Server debug hook. Return True if exception handled, False if ignored.
-    
-    You probably want to wrap this, so you can still handle an error using
-    your framework when it's ignored.
-    """
-    if exc is None: 
-        exc = sys.exc_info()
-    
-    if ignore_all or exc[0] in ignored_exceptions:
-        return False
-    else:
-        ServerError.on = True
-        print("")
-        print("".join(traceback.format_exception(*exc)))
-        return True
-
--- a/bundled/cherrypy/cherrypy/tutorial/README.txt	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-CherryPy Tutorials
-------------------------------------------------------------------------
-
-This is a series of tutorials explaining how to develop dynamic web
-applications using CherryPy. A couple of notes:
-
-  - Each of these tutorials builds on the ones before it. If you're
-    new to CherryPy, we recommend you start with 01_helloworld.py and
-    work your way upwards. :)
-
-  - In most of these tutorials, you will notice that all output is done
-    by returning normal Python strings, often using simple Python
-    variable substitution. In most real-world applications, you will
-    probably want to use a separate template package (like Cheetah,
-    CherryTemplate or XML/XSL).
-
--- a/bundled/cherrypy/cherrypy/tutorial/__init__.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-
-# This is used in test_config to test unrepr of "from A import B"
-thing2 = object()
\ No newline at end of file
--- a/bundled/cherrypy/cherrypy/tutorial/bonus-sqlobject.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,168 +0,0 @@
-'''
-Bonus Tutorial: Using SQLObject
-
-This is a silly little contacts manager application intended to
-demonstrate how to use SQLObject from within a CherryPy2 project. It
-also shows how to use inline Cheetah templates.
-
-SQLObject is an Object/Relational Mapper that allows you to access
-data stored in an RDBMS in a pythonic fashion. You create data objects
-as Python classes and let SQLObject take care of all the nasty details.
-
-This code depends on the latest development version (0.6+) of SQLObject.
-You can get it from the SQLObject Subversion server. You can find all
-necessary information at <http://www.sqlobject.org>. This code will NOT
-work with the 0.5.x version advertised on their website!
-
-This code also depends on a recent version of Cheetah. You can find
-Cheetah at <http://www.cheetahtemplate.org>.
-
-After starting this application for the first time, you will need to
-access the /reset URI in order to create the database table and some
-sample data. Accessing /reset again will drop and re-create the table,
-so you may want to be careful. :-)
-
-This application isn't supposed to be fool-proof, it's not even supposed
-to be very GOOD. Play around with it some, browse the source code, smile.
-
-:)
-
--- Hendrik Mans <hendrik@mans.de>
-'''
-
-import cherrypy
-from Cheetah.Template import Template
-from sqlobject import *
-
-# configure your database connection here
-__connection__ = 'mysql://root:@localhost/test'
-
-# this is our (only) data class.
-class Contact(SQLObject):
-    lastName = StringCol(length = 50, notNone = True)
-    firstName = StringCol(length = 50, notNone = True)
-    phone = StringCol(length = 30, notNone = True, default = '')
-    email = StringCol(length = 30, notNone = True, default = '')
-    url = StringCol(length = 100, notNone = True, default = '')
-
-
-class ContactManager:
-    def index(self):
-        # Let's display a list of all stored contacts.
-        contacts = Contact.select()
-
-        template = Template('''
-            <h2>All Contacts</h2>
-
-            #for $contact in $contacts
-                <a href="mailto:$contact.email">$contact.lastName, $contact.firstName</a>
-                [<a href="./edit?id=$contact.id">Edit</a>]
-                [<a href="./delete?id=$contact.id">Delete</a>]
-                <br/>
-            #end for
-
-            <p>[<a href="./edit">Add new contact</a>]</p>
-        ''', [locals(), globals()])
-
-        return template.respond()
-
-    index.exposed = True
-
-
-    def edit(self, id = 0):
-        # we really want id as an integer. Since GET/POST parameters
-        # are always passed as strings, let's convert it.
-        id = int(id)
-
-        if id > 0:
-            # if an id is specified, we're editing an existing contact.
-            contact = Contact.get(id)
-            title = "Edit Contact"
-        else:
-            # if no id is specified, we're entering a new contact.
-            contact = None
-            title = "New Contact"
-
-
-        # In the following template code, please note that we use
-        # Cheetah's $getVar() construct for the form values. We have
-        # to do this because contact may be set to None (see above).
-        template = Template('''
-            <h2>$title</h2>
-
-            <form action="./store" method="POST">
-                <input type="hidden" name="id" value="$id" />
-                Last Name: <input name="lastName" value="$getVar('contact.lastName', '')" /><br/>
-                First Name: <input name="firstName" value="$getVar('contact.firstName', '')" /><br/>
-                Phone: <input name="phone" value="$getVar('contact.phone', '')" /><br/>
-                Email: <input name="email" value="$getVar('contact.email', '')" /><br/>
-                URL: <input name="url" value="$getVar('contact.url', '')" /><br/>
-                <input type="submit" value="Store" />
-            </form>
-        ''', [locals(), globals()])
-
-        return template.respond()
-
-    edit.exposed = True
-
-
-    def delete(self, id):
-        # Delete the specified contact
-        contact = Contact.get(int(id))
-        contact.destroySelf()
-        return 'Deleted. <a href="./">Return to Index</a>'
-
-    delete.exposed = True
-
-
-    def store(self, lastName, firstName, phone, email, url, id = None):
-        if id and int(id) > 0:
-            # If an id was specified, update an existing contact.
-            contact = Contact.get(int(id))
-
-            # We could set one field after another, but that would
-            # cause multiple UPDATE clauses. So we'll just do it all
-            # in a single pass through the set() method.
-            contact.set(
-                lastName = lastName,
-                firstName = firstName,
-                phone = phone,
-                email = email,
-                url = url)
-        else:
-            # Otherwise, add a new contact.
-            contact = Contact(
-                lastName = lastName,
-                firstName = firstName,
-                phone = phone,
-                email = email,
-                url = url)
-
-        return 'Stored. <a href="./">Return to Index</a>'
-
-    store.exposed = True
-
-
-    def reset(self):
-        # Drop existing table
-        Contact.dropTable(True)
-
-        # Create new table
-        Contact.createTable()
-
-        # Create some sample data
-        Contact(
-            firstName = 'Hendrik',
-            lastName = 'Mans',
-            email = 'hendrik@mans.de',
-            phone = '++49 89 12345678',
-            url = 'http://www.mornography.de')
-
-        return "reset completed!"
-
-    reset.exposed = True
-
-
-print("If you're running this application for the first time, please go to http://localhost:8080/reset once in order to create the database!")
-
-cherrypy.quickstart(ContactManager())
--- a/bundled/cherrypy/cherrypy/tutorial/custom_error.html	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
-  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html>
-<head>
-    <title>403 Unauthorized</title>
-</head>
-    <body>
-        <h2>You can't do that!</h2>
-        <p>%(message)s</p>
-        <p>This is a custom error page that is read from a file.<p>
-        <p>%(traceback)s</p>
-    </body>
-</html>
\ No newline at end of file
Binary file bundled/cherrypy/cherrypy/tutorial/pdf_file.pdf has changed
--- a/bundled/cherrypy/cherrypy/tutorial/tut01_helloworld.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-"""
-Tutorial - Hello World
-
-The most basic (working) CherryPy application possible.
-"""
-
-# Import CherryPy global namespace
-import cherrypy
-
-class HelloWorld:
-    """ Sample request handler class. """
-
-    def index(self):
-        # CherryPy will call this method for the root URI ("/") and send
-        # its return value to the client. Because this is tutorial
-        # lesson number 01, we'll just send something really simple.
-        # How about...
-        return "Hello world!"
-
-    # Expose the index method through the web. CherryPy will never
-    # publish methods that don't have the exposed attribute set to True.
-    index.exposed = True
-
-
-import os.path
-tutconf = os.path.join(os.path.dirname(__file__), 'tutorial.conf')
-
-if __name__ == '__main__':
-    # CherryPy always starts with app.root when trying to map request URIs
-    # to objects, so we need to mount a request handler root. A request
-    # to '/' will be mapped to HelloWorld().index().
-    cherrypy.quickstart(HelloWorld(), config=tutconf)
-else:
-    # This branch is for the test suite; you can ignore it.
-    cherrypy.tree.mount(HelloWorld(), config=tutconf)
--- a/bundled/cherrypy/cherrypy/tutorial/tut02_expose_methods.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-"""
-Tutorial - Multiple methods
-
-This tutorial shows you how to link to other methods of your request
-handler.
-"""
-
-import cherrypy
-
-class HelloWorld:
-    
-    def index(self):
-        # Let's link to another method here.
-        return 'We have an <a href="showMessage">important message</a> for you!'
-    index.exposed = True
-    
-    def showMessage(self):
-        # Here's the important message!
-        return "Hello world!"
-    showMessage.exposed = True
-
-cherrypy.tree.mount(HelloWorld())
-
-if __name__ == '__main__':
-    import os.path
-    thisdir = os.path.dirname(__file__)
-    cherrypy.quickstart(config=os.path.join(thisdir, 'tutorial.conf'))
-
--- a/bundled/cherrypy/cherrypy/tutorial/tut03_get_and_post.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-"""
-Tutorial - Passing variables
-
-This tutorial shows you how to pass GET/POST variables to methods.
-"""
-
-import cherrypy
-
-
-class WelcomePage:
-
-    def index(self):
-        # Ask for the user's name.
-        return '''
-            <form action="greetUser" method="GET">
-            What is your name?
-            <input type="text" name="name" />
-            <input type="submit" />
-            </form>'''
-    index.exposed = True
-    
-    def greetUser(self, name = None):
-        # CherryPy passes all GET and POST variables as method parameters.
-        # It doesn't make a difference where the variables come from, how
-        # large their contents are, and so on.
-        #
-        # You can define default parameter values as usual. In this
-        # example, the "name" parameter defaults to None so we can check
-        # if a name was actually specified.
-        
-        if name:
-            # Greet the user!
-            return "Hey %s, what's up?" % name
-        else:
-            if name is None:
-                # No name was specified
-                return 'Please enter your name <a href="./">here</a>.'
-            else:
-                return 'No, really, enter your name <a href="./">here</a>.'
-    greetUser.exposed = True
-
-
-cherrypy.tree.mount(WelcomePage())
-
-
-if __name__ == '__main__':
-    import os.path
-    thisdir = os.path.dirname(__file__)
-    cherrypy.quickstart(config=os.path.join(thisdir, 'tutorial.conf'))
--- a/bundled/cherrypy/cherrypy/tutorial/tut04_complex_site.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-"""
-Tutorial - Multiple objects
-
-This tutorial shows you how to create a site structure through multiple
-possibly nested request handler objects.
-"""
-
-import cherrypy
-
-
-class HomePage:
-    def index(self):
-        return '''
-            <p>Hi, this is the home page! Check out the other
-            fun stuff on this site:</p>
-            
-            <ul>
-                <li><a href="/joke/">A silly joke</a></li>
-                <li><a href="/links/">Useful links</a></li>
-            </ul>'''
-    index.exposed = True
-
-
-class JokePage:
-    def index(self):
-        return '''
-            <p>"In Python, how do you create a string of random
-            characters?" -- "Read a Perl file!"</p>
-            <p>[<a href="../">Return</a>]</p>'''
-    index.exposed = True
-
-
-class LinksPage:
-    def __init__(self):
-        # Request handler objects can create their own nested request
-        # handler objects. Simply create them inside their __init__
-        # methods!
-        self.extra = ExtraLinksPage()
-    
-    def index(self):
-        # Note the way we link to the extra links page (and back).
-        # As you can see, this object doesn't really care about its
-        # absolute position in the site tree, since we use relative
-        # links exclusively.
-        return '''
-            <p>Here are some useful links:</p>
-            
-            <ul>
-                <li><a href="http://www.cherrypy.org">The CherryPy Homepage</a></li>
-                <li><a href="http://www.python.org">The Python Homepage</a></li>
-            </ul>
-            
-            <p>You can check out some extra useful
-            links <a href="./extra/">here</a>.</p>
-            
-            <p>[<a href="../">Return</a>]</p>
-        '''
-    index.exposed = True
-
-
-class ExtraLinksPage:
-    def index(self):
-        # Note the relative link back to the Links page!
-        return '''
-            <p>Here are some extra useful links:</p>
-            
-            <ul>
-                <li><a href="http://del.icio.us">del.icio.us</a></li>
-                <li><a href="http://www.mornography.de">Hendrik's weblog</a></li>
-            </ul>
-            
-            <p>[<a href="../">Return to links page</a>]</p>'''
-    index.exposed = True
-
-
-# Of course we can also mount request handler objects right here!
-root = HomePage()
-root.joke = JokePage()
-root.links = LinksPage()
-cherrypy.tree.mount(root)
-
-# Remember, we don't need to mount ExtraLinksPage here, because
-# LinksPage does that itself on initialization. In fact, there is
-# no reason why you shouldn't let your root object take care of
-# creating all contained request handler objects.
-
-
-if __name__ == '__main__':
-    import os.path
-    thisdir = os.path.dirname(__file__)
-    cherrypy.quickstart(config=os.path.join(thisdir, 'tutorial.conf'))
-
--- a/bundled/cherrypy/cherrypy/tutorial/tut05_derived_objects.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-"""
-Tutorial - Object inheritance
-
-You are free to derive your request handler classes from any base
-class you wish. In most real-world applications, you will probably
-want to create a central base class used for all your pages, which takes
-care of things like printing a common page header and footer.
-"""
-
-import cherrypy
-
-
-class Page:
-    # Store the page title in a class attribute
-    title = 'Untitled Page'
-    
-    def header(self):
-        return '''
-            <html>
-            <head>
-                <title>%s</title>
-            <head>
-            <body>
-            <h2>%s</h2>
-        ''' % (self.title, self.title)
-    
-    def footer(self):
-        return '''
-            </body>
-            </html>
-        '''
-    
-    # Note that header and footer don't get their exposed attributes
-    # set to True. This isn't necessary since the user isn't supposed
-    # to call header or footer directly; instead, we'll call them from
-    # within the actually exposed handler methods defined in this
-    # class' subclasses.
-
-
-class HomePage(Page):
-    # Different title for this page
-    title = 'Tutorial 5'
-    
-    def __init__(self):
-        # create a subpage
-        self.another = AnotherPage()
-    
-    def index(self):
-        # Note that we call the header and footer methods inherited
-        # from the Page class!
-        return self.header() + '''
-            <p>
-            Isn't this exciting? There's
-            <a href="./another/">another page</a>, too!
-            </p>
-        ''' + self.footer()
-    index.exposed = True
-
-
-class AnotherPage(Page):
-    title = 'Another Page'
-    
-    def index(self):
-        return self.header() + '''
-            <p>
-            And this is the amazing second page!
-            </p>
-        ''' + self.footer()
-    index.exposed = True
-
-
-cherrypy.tree.mount(HomePage())
-
-
-if __name__ == '__main__':
-    import os.path
-    thisdir = os.path.dirname(__file__)
-    cherrypy.quickstart(config=os.path.join(thisdir, 'tutorial.conf'))
--- a/bundled/cherrypy/cherrypy/tutorial/tut06_default_method.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-"""
-Tutorial - The default method
-
-Request handler objects can implement a method called "default" that
-is called when no other suitable method/object could be found.
-Essentially, if CherryPy2 can't find a matching request handler object
-for the given request URI, it will use the default method of the object
-located deepest on the URI path.
-
-Using this mechanism you can easily simulate virtual URI structures
-by parsing the extra URI string, which you can access through
-cherrypy.request.virtualPath.
-
-The application in this tutorial simulates an URI structure looking
-like /users/<username>. Since the <username> bit will not be found (as
-there are no matching methods), it is handled by the default method.
-"""
-
-import cherrypy
-
-
-class UsersPage:
-    
-    def index(self):
-        # Since this is just a stupid little example, we'll simply
-        # display a list of links to random, made-up users. In a real
-        # application, this could be generated from a database result set.
-        return '''
-            <a href="./remi">Remi Delon</a><br/>
-            <a href="./hendrik">Hendrik Mans</a><br/>
-            <a href="./lorenzo">Lorenzo Lamas</a><br/>
-        '''
-    index.exposed = True
-    
-    def default(self, user):
-        # Here we react depending on the virtualPath -- the part of the
-        # path that could not be mapped to an object method. In a real
-        # application, we would probably do some database lookups here
-        # instead of the silly if/elif/else construct.
-        if user == 'remi':
-            out = "Remi Delon, CherryPy lead developer"
-        elif user == 'hendrik':
-            out = "Hendrik Mans, CherryPy co-developer & crazy German"
-        elif user == 'lorenzo':
-            out = "Lorenzo Lamas, famous actor and singer!"
-        else:
-            out = "Unknown user. :-("
-        
-        return '%s (<a href="./">back</a>)' % out
-    default.exposed = True
-
-
-cherrypy.tree.mount(UsersPage())
-
-
-if __name__ == '__main__':
-    import os.path
-    thisdir = os.path.dirname(__file__)
-    cherrypy.quickstart(config=os.path.join(thisdir, 'tutorial.conf'))
--- a/bundled/cherrypy/cherrypy/tutorial/tut07_sessions.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-"""
-Tutorial - Sessions
-
-Storing session data in CherryPy applications is very easy: cherrypy
-provides a dictionary called "session" that represents the session
-data for the current user. If you use RAM based sessions, you can store
-any kind of object into that dictionary; otherwise, you are limited to
-objects that can be pickled.
-"""
-
-import cherrypy
-
-
-class HitCounter:
-    
-    _cp_config = {'tools.sessions.on': True}
-    
-    def index(self):
-        # Increase the silly hit counter
-        count = cherrypy.session.get('count', 0) + 1
-        
-        # Store the new value in the session dictionary
-        cherrypy.session['count'] = count
-        
-        # And display a silly hit count message!
-        return '''
-            During your current session, you've viewed this
-            page %s times! Your life is a patio of fun!
-        ''' % count
-    index.exposed = True
-
-
-cherrypy.tree.mount(HitCounter())
-
-
-if __name__ == '__main__':
-    import os.path
-    thisdir = os.path.dirname(__file__)
-    cherrypy.quickstart(config=os.path.join(thisdir, 'tutorial.conf'))
--- a/bundled/cherrypy/cherrypy/tutorial/tut08_generators_and_yield.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-"""
-Bonus Tutorial: Using generators to return result bodies
-
-Instead of returning a complete result string, you can use the yield
-statement to return one result part after another. This may be convenient
-in situations where using a template package like CherryPy or Cheetah
-would be overkill, and messy string concatenation too uncool. ;-)
-"""
-
-import cherrypy
-
-
-class GeneratorDemo:
-    
-    def header(self):
-        return "<html><body><h2>Generators rule!</h2>"
-    
-    def footer(self):
-        return "</body></html>"
-    
-    def index(self):
-        # Let's make up a list of users for presentation purposes
-        users = ['Remi', 'Carlos', 'Hendrik', 'Lorenzo Lamas']
-        
-        # Every yield line adds one part to the total result body.
-        yield self.header()
-        yield "<h3>List of users:</h3>"
-        
-        for user in users:
-            yield "%s<br/>" % user
-            
-        yield self.footer()
-    index.exposed = True
-
-cherrypy.tree.mount(GeneratorDemo())
-
-
-if __name__ == '__main__':
-    import os.path
-    thisdir = os.path.dirname(__file__)
-    cherrypy.quickstart(config=os.path.join(thisdir, 'tutorial.conf'))
--- a/bundled/cherrypy/cherrypy/tutorial/tut09_files.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-"""
-
-Tutorial: File upload and download
-
-Uploads
--------
-
-When a client uploads a file to a CherryPy application, it's placed
-on disk immediately. CherryPy will pass it to your exposed method
-as an argument (see "myFile" below); that arg will have a "file"
-attribute, which is a handle to the temporary uploaded file.
-If you wish to permanently save the file, you need to read()
-from myFile.file and write() somewhere else.
-
-Note the use of 'enctype="multipart/form-data"' and 'input type="file"'
-in the HTML which the client uses to upload the file.
-
-
-Downloads
----------
-
-If you wish to send a file to the client, you have two options:
-First, you can simply return a file-like object from your page handler.
-CherryPy will read the file and serve it as the content (HTTP body)
-of the response. However, that doesn't tell the client that
-the response is a file to be saved, rather than displayed.
-Use cherrypy.lib.static.serve_file for that; it takes four
-arguments:
-
-serve_file(path, content_type=None, disposition=None, name=None)
-
-Set "name" to the filename that you expect clients to use when they save
-your file. Note that the "name" argument is ignored if you don't also
-provide a "disposition" (usually "attachement"). You can manually set
-"content_type", but be aware that if you also use the encoding tool, it
-may choke if the file extension is not recognized as belonging to a known
-Content-Type. Setting the content_type to "application/x-download" works
-in most cases, and should prompt the user with an Open/Save dialog in
-popular browsers.
-
-"""
-
-import os
-localDir = os.path.dirname(__file__)
-absDir = os.path.join(os.getcwd(), localDir)
-
-import cherrypy
-from cherrypy.lib import static
-
-
-class FileDemo(object):
-    
-    def index(self):
-        return """
-        <html><body>
-            <form action="upload" method="post" enctype="multipart/form-data">
-            filename: <input type="file" name="myFile" /><br />
-            <input type="submit" />
-            </form>
-        </body></html>
-        """
-    index.exposed = True
-    
-    def upload(self, myFile):
-        out = """<html>
-        <body>
-            myFile length: %s<br />
-            myFile filename: %s<br />
-            myFile mime-type: %s
-        </body>
-        </html>"""
-        
-        # Although this just counts the file length, it demonstrates
-        # how to read large files in chunks instead of all at once.
-        # CherryPy reads the uploaded file into a temporary file;
-        # myFile.file.read reads from that.
-        size = 0
-        while True:
-            data = myFile.file.read(8192)
-            if not data:
-                break
-            size += len(data)
-        
-        return out % (size, myFile.filename, myFile.content_type)
-    upload.exposed = True
-    
-    def download(self):
-        path = os.path.join(absDir, "pdf_file.pdf")
-        return static.serve_file(path, "application/x-download",
-                                 "attachment", os.path.basename(path))
-    download.exposed = True
-
-
-cherrypy.tree.mount(FileDemo())
-
-if __name__ == '__main__':
-    import os.path
-    thisdir = os.path.dirname(__file__)
-    cherrypy.quickstart(config=os.path.join(thisdir, 'tutorial.conf'))
--- a/bundled/cherrypy/cherrypy/tutorial/tut10_http_errors.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,77 +0,0 @@
-"""
-
-Tutorial: HTTP errors
-
-HTTPError is used to return an error response to the client.
-CherryPy has lots of options regarding how such errors are
-logged, displayed, and formatted.
-
-"""
-
-import os
-localDir = os.path.dirname(__file__)
-curpath = os.path.normpath(os.path.join(os.getcwd(), localDir))
-
-import cherrypy
-
-
-class HTTPErrorDemo(object):
-    
-    # Set a custom response for 403 errors.
-    _cp_config = {'error_page.403' : os.path.join(curpath, "custom_error.html")}
-    
-    def index(self):
-        # display some links that will result in errors
-        tracebacks = cherrypy.request.show_tracebacks
-        if tracebacks:
-            trace = 'off'
-        else:
-            trace = 'on'
-            
-        return """
-        <html><body>
-            <h2><a href="toggleTracebacks">Toggle tracebacks %s</a></h2>
-            <p><a href="/doesNotExist">Click me; I'm a broken link!</a></p>
-            <p><a href="/error?code=403">Use a custom an error page from a file.</a></p>
-            <p>These errors are explicitly raised by the application:</p>
-            <ul>
-                <li><a href="/error?code=400">400</a></li>
-                <li><a href="/error?code=401">401</a></li>
-                <li><a href="/error?code=402">402</a></li>
-                <li><a href="/error?code=500">500</a></li>
-            </ul>
-            <p><a href="/messageArg">You can also set the response body
-            when you raise an error.</a></p>
-        </body></html>
-        """ % trace
-    index.exposed = True
-    
-    def toggleTracebacks(self):
-        # simple function to toggle tracebacks on and off 
-        tracebacks = cherrypy.request.show_tracebacks
-        cherrypy.config.update({'request.show_tracebacks': not tracebacks})
-        
-        # redirect back to the index
-        raise cherrypy.HTTPRedirect('/')
-    toggleTracebacks.exposed = True
-    
-    def error(self, code):
-        # raise an error based on the get query
-        raise cherrypy.HTTPError(status = code)
-    error.exposed = True
-    
-    def messageArg(self):
-        message = ("If you construct an HTTPError with a 'message' "
-                   "argument, it wil be placed on the error page "
-                   "(underneath the status line by default).")
-        raise cherrypy.HTTPError(500, message=message)
-    messageArg.exposed = True
-
-
-cherrypy.tree.mount(HTTPErrorDemo())
-
-
-if __name__ == '__main__':
-    import os.path
-    thisdir = os.path.dirname(__file__)
-    cherrypy.quickstart(config=os.path.join(thisdir, 'tutorial.conf'))
--- a/bundled/cherrypy/cherrypy/tutorial/tutorial.conf	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-[global]
-server.socket_host = "127.0.0.1"
-server.socket_port = 8080
-server.thread_pool = 10
--- a/bundled/cherrypy/cherrypy/wsgiserver/__init__.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2074 +0,0 @@
-"""A high-speed, production ready, thread pooled, generic HTTP server.
-
-Simplest example on how to use this module directly
-(without using CherryPy's application machinery):
-
-    from cherrypy import wsgiserver
-    
-    def my_crazy_app(environ, start_response):
-        status = '200 OK'
-        response_headers = [('Content-type','text/plain')]
-        start_response(status, response_headers)
-        return ['Hello world!\n']
-    
-    server = wsgiserver.CherryPyWSGIServer(
-                ('0.0.0.0', 8070), my_crazy_app,
-                server_name='www.cherrypy.example')
-    
-The CherryPy WSGI server can serve as many WSGI applications 
-as you want in one instance by using a WSGIPathInfoDispatcher:
-    
-    d = WSGIPathInfoDispatcher({'/': my_crazy_app, '/blog': my_blog_app})
-    server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', 80), d)
-    
-Want SSL support? Just set server.ssl_adapter to an SSLAdapter instance.
-
-This won't call the CherryPy engine (application side) at all, only the
-HTTP server, which is independent from the rest of CherryPy. Don't
-let the name "CherryPyWSGIServer" throw you; the name merely reflects
-its origin, not its coupling.
-
-For those of you wanting to understand internals of this module, here's the
-basic call flow. The server's listening thread runs a very tight loop,
-sticking incoming connections onto a Queue:
-
-    server = CherryPyWSGIServer(...)
-    server.start()
-    while True:
-        tick()
-        # This blocks until a request comes in:
-        child = socket.accept()
-        conn = HTTPConnection(child, ...)
-        server.requests.put(conn)
-
-Worker threads are kept in a pool and poll the Queue, popping off and then
-handling each connection in turn. Each connection can consist of an arbitrary
-number of requests and their responses, so we run a nested loop:
-
-    while True:
-        conn = server.requests.get()
-        conn.communicate()
-        ->  while True:
-                req = HTTPRequest(...)
-                req.parse_request()
-                ->  # Read the Request-Line, e.g. "GET /page HTTP/1.1"
-                    req.rfile.readline()
-                    read_headers(req.rfile, req.inheaders)
-                req.respond()
-                ->  response = app(...)
-                    try:
-                        for chunk in response:
-                            if chunk:
-                                req.write(chunk)
-                    finally:
-                        if hasattr(response, "close"):
-                            response.close()
-                if req.close_connection:
-                    return
-"""
-
-CRLF = '\r\n'
-import os
-import Queue
-import re
-quoted_slash = re.compile("(?i)%2F")
-import rfc822
-import socket
-import sys
-if 'win' in sys.platform and not hasattr(socket, 'IPPROTO_IPV6'):
-    socket.IPPROTO_IPV6 = 41
-try:
-    import cStringIO as StringIO
-except ImportError:
-    import StringIO
-
-_fileobject_uses_str_type = isinstance(socket._fileobject(None)._rbuf, basestring)
-
-import threading
-import time
-import traceback
-from urllib import unquote
-from urlparse import urlparse
-import warnings
-
-import errno
-
-def plat_specific_errors(*errnames):
-    """Return error numbers for all errors in errnames on this platform.
-    
-    The 'errno' module contains different global constants depending on
-    the specific platform (OS). This function will return the list of
-    numeric values for a given list of potential names.
-    """
-    errno_names = dir(errno)
-    nums = [getattr(errno, k) for k in errnames if k in errno_names]
-    # de-dupe the list
-    return dict.fromkeys(nums).keys()
-
-socket_error_eintr = plat_specific_errors("EINTR", "WSAEINTR")
-
-socket_errors_to_ignore = plat_specific_errors(
-    "EPIPE",
-    "EBADF", "WSAEBADF",
-    "ENOTSOCK", "WSAENOTSOCK",
-    "ETIMEDOUT", "WSAETIMEDOUT",
-    "ECONNREFUSED", "WSAECONNREFUSED",
-    "ECONNRESET", "WSAECONNRESET",
-    "ECONNABORTED", "WSAECONNABORTED",
-    "ENETRESET", "WSAENETRESET",
-    "EHOSTDOWN", "EHOSTUNREACH",
-    )
-socket_errors_to_ignore.append("timed out")
-socket_errors_to_ignore.append("The read operation timed out")
-
-socket_errors_nonblocking = plat_specific_errors(
-    'EAGAIN', 'EWOULDBLOCK', 'WSAEWOULDBLOCK')
-
-comma_separated_headers = ['Accept', 'Accept-Charset', 'Accept-Encoding',
-    'Accept-Language', 'Accept-Ranges', 'Allow', 'Cache-Control',
-    'Connection', 'Content-Encoding', 'Content-Language', 'Expect',
-    'If-Match', 'If-None-Match', 'Pragma', 'Proxy-Authenticate', 'TE',
-    'Trailer', 'Transfer-Encoding', 'Upgrade', 'Vary', 'Via', 'Warning',
-    'WWW-Authenticate']
-
-
-def read_headers(rfile, hdict=None):
-    """Read headers from the given stream into the given header dict.
-    
-    If hdict is None, a new header dict is created. Returns the populated
-    header dict.
-    
-    Headers which are repeated are folded together using a comma if their
-    specification so dictates.
-    
-    This function raises ValueError when the read bytes violate the HTTP spec.
-    You should probably return "400 Bad Request" if this happens.
-    """
-    if hdict is None:
-        hdict = {}
-    
-    while True:
-        line = rfile.readline()
-        if not line:
-            # No more data--illegal end of headers
-            raise ValueError("Illegal end of headers.")
-        
-        if line == CRLF:
-            # Normal end of headers
-            break
-        if not line.endswith(CRLF):
-            raise ValueError("HTTP requires CRLF terminators")
-        
-        if line[0] in ' \t':
-            # It's a continuation line.
-            v = line.strip()
-        else:
-            try:
-                k, v = line.split(":", 1)
-            except ValueError:
-                raise ValueError("Illegal header line.")
-            # TODO: what about TE and WWW-Authenticate?
-            k = k.strip().title()
-            v = v.strip()
-            hname = k
-        
-        if k in comma_separated_headers:
-            existing = hdict.get(hname)
-            if existing:
-                v = ", ".join((existing, v))
-        hdict[hname] = v
-    
-    return hdict
-
-
-class MaxSizeExceeded(Exception):
-    pass
-
-class SizeCheckWrapper(object):
-    """Wraps a file-like object, raising MaxSizeExceeded if too large."""
-    
-    def __init__(self, rfile, maxlen):
-        self.rfile = rfile
-        self.maxlen = maxlen
-        self.bytes_read = 0
-    
-    def _check_length(self):
-        if self.maxlen and self.bytes_read > self.maxlen:
-            raise MaxSizeExceeded()
-    
-    def read(self, size=None):
-        data = self.rfile.read(size)
-        self.bytes_read += len(data)
-        self._check_length()
-        return data
-    
-    def readline(self, size=None):
-        if size is not None:
-            data = self.rfile.readline(size)
-            self.bytes_read += len(data)
-            self._check_length()
-            return data
-        
-        # User didn't specify a size ...
-        # We read the line in chunks to make sure it's not a 100MB line !
-        res = []
-        while True:
-            data = self.rfile.readline(256)
-            self.bytes_read += len(data)
-            self._check_length()
-            res.append(data)
-            # See http://www.cherrypy.org/ticket/421
-            if len(data) < 256 or data[-1:] == "\n":
-                return ''.join(res)
-    
-    def readlines(self, sizehint=0):
-        # Shamelessly stolen from StringIO
-        total = 0
-        lines = []
-        line = self.readline()
-        while line:
-            lines.append(line)
-            total += len(line)
-            if 0 < sizehint <= total:
-                break
-            line = self.readline()
-        return lines
-    
-    def close(self):
-        self.rfile.close()
-    
-    def __iter__(self):
-        return self
-    
-    def next(self):
-        data = self.rfile.next()
-        self.bytes_read += len(data)
-        self._check_length()
-        return data
-
-
-class KnownLengthRFile(object):
-    """Wraps a file-like object, returning an empty string when exhausted."""
-    
-    def __init__(self, rfile, content_length):
-        self.rfile = rfile
-        self.remaining = content_length
-    
-    def read(self, size=None):
-        if self.remaining == 0:
-            return ''
-        if size is None:
-            size = self.remaining
-        else:
-            size = min(size, self.remaining)
-        
-        data = self.rfile.read(size)
-        self.remaining -= len(data)
-        return data
-    
-    def readline(self, size=None):
-        if self.remaining == 0:
-            return ''
-        if size is None:
-            size = self.remaining
-        else:
-            size = min(size, self.remaining)
-        
-        data = self.rfile.readline(size)
-        self.remaining -= len(data)
-        return data
-    
-    def readlines(self, sizehint=0):
-        # Shamelessly stolen from StringIO
-        total = 0
-        lines = []
-        line = self.readline(sizehint)
-        while line:
-            lines.append(line)
-            total += len(line)
-            if 0 < sizehint <= total:
-                break
-            line = self.readline(sizehint)
-        return lines
-    
-    def close(self):
-        self.rfile.close()
-    
-    def __iter__(self):
-        return self
-    
-    def __next__(self):
-        data = next(self.rfile)
-        self.remaining -= len(data)
-        return data
-
-
-class MaxSizeExceeded(Exception):
-    pass
-
-
-class ChunkedRFile(object):
-    """Wraps a file-like object, returning an empty string when exhausted.
-    
-    This class is intended to provide a conforming wsgi.input value for
-    request entities that have been encoded with the 'chunked' transfer
-    encoding.
-    """
-    
-    def __init__(self, rfile, maxlen, bufsize=8192):
-        self.rfile = rfile
-        self.maxlen = maxlen
-        self.bytes_read = 0
-        self.buffer = ''
-        self.bufsize = bufsize
-        self.closed = False
-    
-    def _fetch(self):
-        if self.closed:
-            return
-        
-        line = self.rfile.readline()
-        self.bytes_read += len(line)
-        
-        if self.maxlen and self.bytes_read > self.maxlen:
-            raise MaxSizeExceeded("Request Entity Too Large", self.maxlen)
-        
-        line = line.strip().split(";", 1)
-        
-        try:
-            chunk_size = line.pop(0)
-            chunk_size = int(chunk_size, 16)
-        except ValueError:
-            raise ValueError("Bad chunked transfer size: " + repr(chunk_size))
-        
-        if chunk_size <= 0:
-            self.closed = True
-            return
-        
-##            if line: chunk_extension = line[0]
-        
-        if self.maxlen and self.bytes_read + chunk_size > self.maxlen:
-            raise IOError("Request Entity Too Large")
-        
-        chunk = self.rfile.read(chunk_size)
-        self.bytes_read += len(chunk)
-        self.buffer += chunk
-        
-        crlf = self.rfile.read(2)
-        if crlf != CRLF:
-            raise ValueError(
-                 "Bad chunked transfer coding (expected '\\r\\n', "
-                 "got " + repr(crlf) + ")")
-    
-    def read(self, size=None):
-        data = ''
-        while True:
-            if size and len(data) >= size:
-                return data
-            
-            if not self.buffer:
-                self._fetch()
-                if not self.buffer:
-                    # EOF
-                    return data
-            
-            if size:
-                remaining = size - len(data)
-                data += self.buffer[:remaining]
-                self.buffer = self.buffer[remaining:]
-            else:
-                data += self.buffer
-    
-    def readline(self, size=None):
-        data = ''
-        while True:
-            if size and len(data) >= size:
-                return data
-            
-            if not self.buffer:
-                self._fetch()
-                if not self.buffer:
-                    # EOF
-                    return data
-            
-            newline_pos = self.buffer.find('\n')
-            if size:
-                if newline_pos == -1:
-                    remaining = size - len(data)
-                    data += self.buffer[:remaining]
-                    self.buffer = self.buffer[remaining:]
-                else:
-                    remaining = min(size - len(data), newline_pos)
-                    data += self.buffer[:remaining]
-                    self.buffer = self.buffer[remaining:]
-            else:
-                if newline_pos == -1:
-                    data += self.buffer
-                else:
-                    data += self.buffer[:newline_pos]
-                    self.buffer = self.buffer[newline_pos:]
-    
-    def readlines(self, sizehint=0):
-        # Shamelessly stolen from StringIO
-        total = 0
-        lines = []
-        line = self.readline(sizehint)
-        while line:
-            lines.append(line)
-            total += len(line)
-            if 0 < sizehint <= total:
-                break
-            line = self.readline(sizehint)
-        return lines
-    
-    def read_trailer_lines(self):
-        if not self.closed:
-            raise ValueError(
-                "Cannot read trailers until the request body has been read.")
-        
-        while True:
-            line = self.rfile.readline()
-            if not line:
-                # No more data--illegal end of headers
-                raise ValueError("Illegal end of headers.")
-            
-            self.bytes_read += len(line)
-            if self.maxlen and self.bytes_read > self.maxlen:
-                raise IOError("Request Entity Too Large")
-            
-            if line == CRLF:
-                # Normal end of headers
-                break
-            if not line.endswith(CRLF):
-                raise ValueError("HTTP requires CRLF terminators")
-            
-            yield line
-    
-    def close(self):
-        self.rfile.close()
-    
-    def __iter__(self):
-        # Shamelessly stolen from StringIO
-        total = 0
-        line = self.readline(sizehint)
-        while line:
-            yield line
-            total += len(line)
-            if 0 < sizehint <= total:
-                break
-            line = self.readline(sizehint)
-
-
-class HTTPRequest(object):
-    """An HTTP Request (and response).
-    
-    A single HTTP connection may consist of multiple request/response pairs.
-    
-    server: the Server object which is receiving this request.
-    conn: the HTTPConnection object on which this request connected.
-    
-    inheaders: a dict of request headers.
-    outheaders: a list of header tuples to write in the response.
-    ready: when True, the request has been parsed and is ready to begin
-        generating the response. When False, signals the calling Connection
-        that the response should not be generated and the connection should
-        close.
-    close_connection: signals the calling Connection that the request
-        should close. This does not imply an error! The client and/or
-        server may each request that the connection be closed.
-    chunked_write: if True, output will be encoded with the "chunked"
-        transfer-coding. This value is set automatically inside
-        send_headers.
-    """
-    
-    def __init__(self, server, conn):
-        self.server= server
-        self.conn = conn
-        
-        self.ready = False
-        self.started_request = False
-        self.scheme = "http"
-        if self.server.ssl_adapter is not None:
-            self.scheme = "https"
-        self.inheaders = {}
-        
-        self.status = ""
-        self.outheaders = []
-        self.sent_headers = False
-        self.close_connection = False
-        self.chunked_write = False
-    
-    def parse_request(self):
-        """Parse the next HTTP request start-line and message-headers."""
-        self.rfile = SizeCheckWrapper(self.conn.rfile,
-                                      self.server.max_request_header_size)
-        try:
-            self._parse_request()
-        except MaxSizeExceeded:
-            self.simple_response("413 Request Entity Too Large")
-            return
-    
-    def _parse_request(self):
-        # HTTP/1.1 connections are persistent by default. If a client
-        # requests a page, then idles (leaves the connection open),
-        # then rfile.readline() will raise socket.error("timed out").
-        # Note that it does this based on the value given to settimeout(),
-        # and doesn't need the client to request or acknowledge the close
-        # (although your TCP stack might suffer for it: cf Apache's history
-        # with FIN_WAIT_2).
-        request_line = self.rfile.readline()
-        
-        # Set started_request to True so communicate() knows to send 408
-        # from here on out.
-        self.started_request = True
-        if not request_line:
-            # Force self.ready = False so the connection will close.
-            self.ready = False
-            return
-        
-        if request_line == CRLF:
-            # RFC 2616 sec 4.1: "...if the server is reading the protocol
-            # stream at the beginning of a message and receives a CRLF
-            # first, it should ignore the CRLF."
-            # But only ignore one leading line! else we enable a DoS.
-            request_line = self.rfile.readline()
-            if not request_line:
-                self.ready = False
-                return
-        
-        if not request_line.endswith(CRLF):
-            self.simple_response(400, "HTTP requires CRLF terminators")
-            return
-        
-        try:
-            method, uri, req_protocol = request_line.strip().split(" ", 2)
-        except ValueError:
-            self.simple_response(400, "Malformed Request-Line")
-            return
-        
-        self.uri = uri
-        self.method = method
-        
-        # uri may be an abs_path (including "http://host.domain.tld");
-        scheme, authority, path = self.parse_request_uri(uri)
-        if '#' in path:
-            self.simple_response("400 Bad Request",
-                                 "Illegal #fragment in Request-URI.")
-            return
-        
-        if scheme:
-            self.scheme = scheme
-        
-        qs = ''
-        if '?' in path:
-            path, qs = path.split('?', 1)
-        
-        # Unquote the path+params (e.g. "/this%20path" -> "/this path").
-        # http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
-        #
-        # But note that "...a URI must be separated into its components
-        # before the escaped characters within those components can be
-        # safely decoded." http://www.ietf.org/rfc/rfc2396.txt, sec 2.4.2
-        # Therefore, "/this%2Fpath" becomes "/this%2Fpath", not "/this/path".
-        try:
-            atoms = [unquote(x) for x in quoted_slash.split(path)]
-        except ValueError, ex:
-            self.simple_response("400 Bad Request", ex.args[0])
-            return
-        path = "%2F".join(atoms)
-        self.path = path
-        
-        # Note that, like wsgiref and most other HTTP servers,
-        # we "% HEX HEX"-unquote the path but not the query string.
-        self.qs = qs
-        
-        # Compare request and server HTTP protocol versions, in case our
-        # server does not support the requested protocol. Limit our output
-        # to min(req, server). We want the following output:
-        #     request    server     actual written   supported response
-        #     protocol   protocol  response protocol    feature set
-        # a     1.0        1.0           1.0                1.0
-        # b     1.0        1.1           1.1                1.0
-        # c     1.1        1.0           1.0                1.0
-        # d     1.1        1.1           1.1                1.1
-        # Notice that, in (b), the response will be "HTTP/1.1" even though
-        # the client only understands 1.0. RFC 2616 10.5.6 says we should
-        # only return 505 if the _major_ version is different.
-        rp = int(req_protocol[5]), int(req_protocol[7])
-        sp = int(self.server.protocol[5]), int(self.server.protocol[7])
-        
-        if sp[0] != rp[0]:
-            self.simple_response("505 HTTP Version Not Supported")
-            return
-        self.request_protocol = req_protocol
-        self.response_protocol = "HTTP/%s.%s" % min(rp, sp)
-        
-        # then all the http headers
-        try:
-            read_headers(self.rfile, self.inheaders)
-        except ValueError, ex:
-            self.simple_response("400 Bad Request", ex.args[0])
-            return
-        
-        mrbs = self.server.max_request_body_size
-        if mrbs and int(self.inheaders.get("Content-Length", 0)) > mrbs:
-            self.simple_response("413 Request Entity Too Large")
-            return
-        
-        # Persistent connection support
-        if self.response_protocol == "HTTP/1.1":
-            # Both server and client are HTTP/1.1
-            if self.inheaders.get("Connection", "") == "close":
-                self.close_connection = True
-        else:
-            # Either the server or client (or both) are HTTP/1.0
-            if self.inheaders.get("Connection", "") != "Keep-Alive":
-                self.close_connection = True
-        
-        # Transfer-Encoding support
-        te = None
-        if self.response_protocol == "HTTP/1.1":
-            te = self.inheaders.get("Transfer-Encoding")
-            if te:
-                te = [x.strip().lower() for x in te.split(",") if x.strip()]
-        
-        self.chunked_read = False
-        
-        if te:
-            for enc in te:
-                if enc == "chunked":
-                    self.chunked_read = True
-                else:
-                    # Note that, even if we see "chunked", we must reject
-                    # if there is an extension we don't recognize.
-                    self.simple_response("501 Unimplemented")
-                    self.close_connection = True
-                    return
-        
-        # From PEP 333:
-        # "Servers and gateways that implement HTTP 1.1 must provide
-        # transparent support for HTTP 1.1's "expect/continue" mechanism.
-        # This may be done in any of several ways:
-        #   1. Respond to requests containing an Expect: 100-continue request
-        #      with an immediate "100 Continue" response, and proceed normally.
-        #   2. Proceed with the request normally, but provide the application
-        #      with a wsgi.input stream that will send the "100 Continue"
-        #      response if/when the application first attempts to read from
-        #      the input stream. The read request must then remain blocked
-        #      until the client responds.
-        #   3. Wait until the client decides that the server does not support
-        #      expect/continue, and sends the request body on its own.
-        #      (This is suboptimal, and is not recommended.)
-        #
-        # We used to do 3, but are now doing 1. Maybe we'll do 2 someday,
-        # but it seems like it would be a big slowdown for such a rare case.
-        if self.inheaders.get("Expect", "") == "100-continue":
-            # Don't use simple_response here, because it emits headers
-            # we don't want. See http://www.cherrypy.org/ticket/951
-            msg = self.server.protocol + " 100 Continue\r\n\r\n"
-            try:
-                self.conn.wfile.sendall(msg)
-            except socket.error, x:
-                if x.args[0] not in socket_errors_to_ignore:
-                    raise
-        
-        self.ready = True
-    
-    def parse_request_uri(self, uri):
-        """Parse a Request-URI into (scheme, authority, path).
-        
-        Note that Request-URI's must be one of:
-            
-            Request-URI    = "*" | absoluteURI | abs_path | authority
-        
-        Therefore, a Request-URI which starts with a double forward-slash
-        cannot be a "net_path":
-        
-            net_path      = "//" authority [ abs_path ]
-        
-        Instead, it must be interpreted as an "abs_path" with an empty first
-        path segment:
-        
-            abs_path      = "/"  path_segments
-            path_segments = segment *( "/" segment )
-            segment       = *pchar *( ";" param )
-            param         = *pchar
-        """
-        if uri == "*":
-            return None, None, uri
-        
-        i = uri.find('://')
-        if i > 0 and '?' not in uri[:i]:
-            # An absoluteURI.
-            # If there's a scheme (and it must be http or https), then:
-            # http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
-            scheme, remainder = uri[:i].lower(), uri[i + 3:]
-            authority, path = remainder.split("/", 1)
-            return scheme, authority, path
-        
-        if uri.startswith('/'):
-            # An abs_path.
-            return None, None, uri
-        else:
-            # An authority.
-            return None, uri, None
-    
-    def respond(self):
-        """Call the gateway and write its iterable output."""
-        mrbs = self.server.max_request_body_size
-        if self.chunked_read:
-            self.rfile = ChunkedRFile(self.conn.rfile, mrbs)
-        else:
-            cl = int(self.inheaders.get("Content-Length", 0))
-            if mrbs and mrbs < cl:
-                if not self.sent_headers:
-                    self.simple_response("413 Request Entity Too Large")
-                return
-            self.rfile = KnownLengthRFile(self.conn.rfile, cl)
-        
-        self.server.gateway(self).respond()
-        
-        if (self.ready and not self.sent_headers):
-            self.sent_headers = True
-            self.send_headers()
-        if self.chunked_write:
-            self.conn.wfile.sendall("0\r\n\r\n")
-    
-    def simple_response(self, status, msg=""):
-        """Write a simple response back to the client."""
-        status = str(status)
-        buf = [self.server.protocol + " " +
-               status + CRLF,
-               "Content-Length: %s\r\n" % len(msg),
-               "Content-Type: text/plain\r\n"]
-        
-        if status[:3] == "413" and self.response_protocol == 'HTTP/1.1':
-            # Request Entity Too Large
-            self.close_connection = True
-            buf.append("Connection: close\r\n")
-        
-        buf.append(CRLF)
-        if msg:
-            if isinstance(msg, unicode):
-                msg = msg.encode("ISO-8859-1")
-            buf.append(msg)
-        
-        try:
-            self.conn.wfile.sendall("".join(buf))
-        except socket.error, x:
-            if x.args[0] not in socket_errors_to_ignore:
-                raise
-    
-    def write(self, chunk):
-        """Write unbuffered data to the client."""
-        if self.chunked_write and chunk:
-            buf = [hex(len(chunk))[2:], CRLF, chunk, CRLF]
-            self.conn.wfile.sendall("".join(buf))
-        else:
-            self.conn.wfile.sendall(chunk)
-    
-    def send_headers(self):
-        """Assert, process, and send the HTTP response message-headers.
-        
-        You must set self.status, and self.outheaders before calling this.
-        """
-        hkeys = [key.lower() for key, value in self.outheaders]
-        status = int(self.status[:3])
-        
-        if status == 413:
-            # Request Entity Too Large. Close conn to avoid garbage.
-            self.close_connection = True
-        elif "content-length" not in hkeys:
-            # "All 1xx (informational), 204 (no content),
-            # and 304 (not modified) responses MUST NOT
-            # include a message-body." So no point chunking.
-            if status < 200 or status in (204, 205, 304):
-                pass
-            else:
-                if (self.response_protocol == 'HTTP/1.1'
-                    and self.method != 'HEAD'):
-                    # Use the chunked transfer-coding
-                    self.chunked_write = True
-                    self.outheaders.append(("Transfer-Encoding", "chunked"))
-                else:
-                    # Closing the conn is the only way to determine len.
-                    self.close_connection = True
-        
-        if "connection" not in hkeys:
-            if self.response_protocol == 'HTTP/1.1':
-                # Both server and client are HTTP/1.1 or better
-                if self.close_connection:
-                    self.outheaders.append(("Connection", "close"))
-            else:
-                # Server and/or client are HTTP/1.0
-                if not self.close_connection:
-                    self.outheaders.append(("Connection", "Keep-Alive"))
-        
-        if (not self.close_connection) and (not self.chunked_read):
-            # Read any remaining request body data on the socket.
-            # "If an origin server receives a request that does not include an
-            # Expect request-header field with the "100-continue" expectation,
-            # the request includes a request body, and the server responds
-            # with a final status code before reading the entire request body
-            # from the transport connection, then the server SHOULD NOT close
-            # the transport connection until it has read the entire request,
-            # or until the client closes the connection. Otherwise, the client
-            # might not reliably receive the response message. However, this
-            # requirement is not be construed as preventing a server from
-            # defending itself against denial-of-service attacks, or from
-            # badly broken client implementations."
-            remaining = getattr(self.rfile, 'remaining', 0)
-            if remaining > 0:
-                self.rfile.read(remaining)
-        
-        if "date" not in hkeys:
-            self.outheaders.append(("Date", rfc822.formatdate()))
-        
-        if "server" not in hkeys:
-            self.outheaders.append(("Server", self.server.server_name))
-        
-        buf = [self.server.protocol + " " + self.status + CRLF]
-        for k, v in self.outheaders:
-            buf.append(k + ": " + v + CRLF)
-        buf.append(CRLF)
-        self.conn.wfile.sendall("".join(buf))
-
-
-class NoSSLError(Exception):
-    """Exception raised when a client speaks HTTP to an HTTPS socket."""
-    pass
-
-
-class FatalSSLAlert(Exception):
-    """Exception raised when the SSL implementation signals a fatal alert."""
-    pass
-
-
-if not _fileobject_uses_str_type:
-    class CP_fileobject(socket._fileobject):
-        """Faux file object attached to a socket object."""
-
-        def sendall(self, data):
-            """Sendall for non-blocking sockets."""
-            while data:
-                try:
-                    bytes_sent = self.send(data)
-                    data = data[bytes_sent:]
-                except socket.error, e:
-                    if e.args[0] not in socket_errors_nonblocking:
-                        raise
-
-        def send(self, data):
-            return self._sock.send(data)
-
-        def flush(self):
-            if self._wbuf:
-                buffer = "".join(self._wbuf)
-                self._wbuf = []
-                self.sendall(buffer)
-
-        def recv(self, size):
-            while True:
-                try:
-                    return self._sock.recv(size)
-                except socket.error, e:
-                    if (e.args[0] not in socket_errors_nonblocking
-                        and e.args[0] not in socket_error_eintr):
-                        raise
-
-        def read(self, size=-1):
-            # Use max, disallow tiny reads in a loop as they are very inefficient.
-            # We never leave read() with any leftover data from a new recv() call
-            # in our internal buffer.
-            rbufsize = max(self._rbufsize, self.default_bufsize)
-            # Our use of StringIO rather than lists of string objects returned by
-            # recv() minimizes memory usage and fragmentation that occurs when
-            # rbufsize is large compared to the typical return value of recv().
-            buf = self._rbuf
-            buf.seek(0, 2)  # seek end
-            if size < 0:
-                # Read until EOF
-                self._rbuf = StringIO.StringIO()  # reset _rbuf.  we consume it via buf.
-                while True:
-                    data = self.recv(rbufsize)
-                    if not data:
-                        break
-                    buf.write(data)
-                return buf.getvalue()
-            else:
-                # Read until size bytes or EOF seen, whichever comes first
-                buf_len = buf.tell()
-                if buf_len >= size:
-                    # Already have size bytes in our buffer?  Extract and return.
-                    buf.seek(0)
-                    rv = buf.read(size)
-                    self._rbuf = StringIO.StringIO()
-                    self._rbuf.write(buf.read())
-                    return rv
-
-                self._rbuf = StringIO.StringIO()  # reset _rbuf.  we consume it via buf.
-                while True:
-                    left = size - buf_len
-                    # recv() will malloc the amount of memory given as its
-                    # parameter even though it often returns much less data
-                    # than that.  The returned data string is short lived
-                    # as we copy it into a StringIO and free it.  This avoids
-                    # fragmentation issues on many platforms.
-                    data = self.recv(left)
-                    if not data:
-                        break
-                    n = len(data)
-                    if n == size and not buf_len:
-                        # Shortcut.  Avoid buffer data copies when:
-                        # - We have no data in our buffer.
-                        # AND
-                        # - Our call to recv returned exactly the
-                        #   number of bytes we were asked to read.
-                        return data
-                    if n == left:
-                        buf.write(data)
-                        del data  # explicit free
-                        break
-                    assert n <= left, "recv(%d) returned %d bytes" % (left, n)
-                    buf.write(data)
-                    buf_len += n
-                    del data  # explicit free
-                    #assert buf_len == buf.tell()
-                return buf.getvalue()
-
-        def readline(self, size=-1):
-            buf = self._rbuf
-            buf.seek(0, 2)  # seek end
-            if buf.tell() > 0:
-                # check if we already have it in our buffer
-                buf.seek(0)
-                bline = buf.readline(size)
-                if bline.endswith('\n') or len(bline) == size:
-                    self._rbuf = StringIO.StringIO()
-                    self._rbuf.write(buf.read())
-                    return bline
-                del bline
-            if size < 0:
-                # Read until \n or EOF, whichever comes first
-                if self._rbufsize <= 1:
-                    # Speed up unbuffered case
-                    buf.seek(0)
-                    buffers = [buf.read()]
-                    self._rbuf = StringIO.StringIO()  # reset _rbuf.  we consume it via buf.
-                    data = None
-                    recv = self.recv
-                    while data != "\n":
-                        data = recv(1)
-                        if not data:
-                            break
-                        buffers.append(data)
-                    return "".join(buffers)
-
-                buf.seek(0, 2)  # seek end
-                self._rbuf = StringIO.StringIO()  # reset _rbuf.  we consume it via buf.
-                while True:
-                    data = self.recv(self._rbufsize)
-                    if not data:
-                        break
-                    nl = data.find('\n')
-                    if nl >= 0:
-                        nl += 1
-                        buf.write(data[:nl])
-                        self._rbuf.write(data[nl:])
-                        del data
-                        break
-                    buf.write(data)
-                return buf.getvalue()
-            else:
-                # Read until size bytes or \n or EOF seen, whichever comes first
-                buf.seek(0, 2)  # seek end
-                buf_len = buf.tell()
-                if buf_len >= size:
-                    buf.seek(0)
-                    rv = buf.read(size)
-                    self._rbuf = StringIO.StringIO()
-                    self._rbuf.write(buf.read())
-                    return rv
-                self._rbuf = StringIO.StringIO()  # reset _rbuf.  we consume it via buf.
-                while True:
-                    data = self.recv(self._rbufsize)
-                    if not data:
-                        break
-                    left = size - buf_len
-                    # did we just receive a newline?
-                    nl = data.find('\n', 0, left)
-                    if nl >= 0:
-                        nl += 1
-                        # save the excess data to _rbuf
-                        self._rbuf.write(data[nl:])
-                        if buf_len:
-                            buf.write(data[:nl])
-                            break
-                        else:
-                            # Shortcut.  Avoid data copy through buf when returning
-                            # a substring of our first recv().
-                            return data[:nl]
-                    n = len(data)
-                    if n == size and not buf_len:
-                        # Shortcut.  Avoid data copy through buf when
-                        # returning exactly all of our first recv().
-                        return data
-                    if n >= left:
-                        buf.write(data[:left])
-                        self._rbuf.write(data[left:])
-                        break
-                    buf.write(data)
-                    buf_len += n
-                    #assert buf_len == buf.tell()
-                return buf.getvalue()
-
-else:
-    class CP_fileobject(socket._fileobject):
-        """Faux file object attached to a socket object."""
-
-        def sendall(self, data):
-            """Sendall for non-blocking sockets."""
-            while data:
-                try:
-                    bytes_sent = self.send(data)
-                    data = data[bytes_sent:]
-                except socket.error, e:
-                    if e.args[0] not in socket_errors_nonblocking:
-                        raise
-
-        def send(self, data):
-            return self._sock.send(data)
-
-        def flush(self):
-            if self._wbuf:
-                buffer = "".join(self._wbuf)
-                self._wbuf = []
-                self.sendall(buffer)
-
-        def recv(self, size):
-            while True:
-                try:
-                    return self._sock.recv(size)
-                except socket.error, e:
-                    if (e.args[0] not in socket_errors_nonblocking
-                        and e.args[0] not in socket_error_eintr):
-                        raise
-
-        def read(self, size=-1):
-            if size < 0:
-                # Read until EOF
-                buffers = [self._rbuf]
-                self._rbuf = ""
-                if self._rbufsize <= 1:
-                    recv_size = self.default_bufsize
-                else:
-                    recv_size = self._rbufsize
-
-                while True:
-                    data = self.recv(recv_size)
-                    if not data:
-                        break
-                    buffers.append(data)
-                return "".join(buffers)
-            else:
-                # Read until size bytes or EOF seen, whichever comes first
-                data = self._rbuf
-                buf_len = len(data)
-                if buf_len >= size:
-                    self._rbuf = data[size:]
-                    return data[:size]
-                buffers = []
-                if data:
-                    buffers.append(data)
-                self._rbuf = ""
-                while True:
-                    left = size - buf_len
-                    recv_size = max(self._rbufsize, left)
-                    data = self.recv(recv_size)
-                    if not data:
-                        break
-                    buffers.append(data)
-                    n = len(data)
-                    if n >= left:
-                        self._rbuf = data[left:]
-                        buffers[-1] = data[:left]
-                        break
-                    buf_len += n
-                return "".join(buffers)
-
-        def readline(self, size=-1):
-            data = self._rbuf
-            if size < 0:
-                # Read until \n or EOF, whichever comes first
-                if self._rbufsize <= 1:
-                    # Speed up unbuffered case
-                    assert data == ""
-                    buffers = []
-                    while data != "\n":
-                        data = self.recv(1)
-                        if not data:
-                            break
-                        buffers.append(data)
-                    return "".join(buffers)
-                nl = data.find('\n')
-                if nl >= 0:
-                    nl += 1
-                    self._rbuf = data[nl:]
-                    return data[:nl]
-                buffers = []
-                if data:
-                    buffers.append(data)
-                self._rbuf = ""
-                while True:
-                    data = self.recv(self._rbufsize)
-                    if not data:
-                        break
-                    buffers.append(data)
-                    nl = data.find('\n')
-                    if nl >= 0:
-                        nl += 1
-                        self._rbuf = data[nl:]
-                        buffers[-1] = data[:nl]
-                        break
-                return "".join(buffers)
-            else:
-                # Read until size bytes or \n or EOF seen, whichever comes first
-                nl = data.find('\n', 0, size)
-                if nl >= 0:
-                    nl += 1
-                    self._rbuf = data[nl:]
-                    return data[:nl]
-                buf_len = len(data)
-                if buf_len >= size:
-                    self._rbuf = data[size:]
-                    return data[:size]
-                buffers = []
-                if data:
-                    buffers.append(data)
-                self._rbuf = ""
-                while True:
-                    data = self.recv(self._rbufsize)
-                    if not data:
-                        break
-                    buffers.append(data)
-                    left = size - buf_len
-                    nl = data.find('\n', 0, left)
-                    if nl >= 0:
-                        nl += 1
-                        self._rbuf = data[nl:]
-                        buffers[-1] = data[:nl]
-                        break
-                    n = len(data)
-                    if n >= left:
-                        self._rbuf = data[left:]
-                        buffers[-1] = data[:left]
-                        break
-                    buf_len += n
-                return "".join(buffers)
-
-
-class HTTPConnection(object):
-    """An HTTP connection (active socket).
-    
-    server: the Server object which received this connection.
-    socket: the raw socket object (usually TCP) for this connection.
-    makefile: a fileobject class for reading from the socket.
-    """
-    
-    remote_addr = None
-    remote_port = None
-    ssl_env = None
-    rbufsize = -1
-    RequestHandlerClass = HTTPRequest
-    
-    def __init__(self, server, sock, makefile=CP_fileobject):
-        self.server = server
-        self.socket = sock
-        self.rfile = makefile(sock, "rb", self.rbufsize)
-        self.wfile = makefile(sock, "wb", -1)
-    
-    def communicate(self):
-        """Read each request and respond appropriately."""
-        request_seen = False
-        try:
-            while True:
-                # (re)set req to None so that if something goes wrong in
-                # the RequestHandlerClass constructor, the error doesn't
-                # get written to the previous request.
-                req = None
-                req = self.RequestHandlerClass(self.server, self)
-                
-                # This order of operations should guarantee correct pipelining.
-                req.parse_request()
-                if not req.ready:
-                    # Something went wrong in the parsing (and the server has
-                    # probably already made a simple_response). Return and
-                    # let the conn close.
-                    return
-                
-                request_seen = True
-                req.respond()
-                if req.close_connection:
-                    return
-        except socket.error, e:
-            errnum = e.args[0]
-            if errnum == 'timed out':
-                # Don't error if we're between requests; only error
-                # if 1) no request has been started at all, or 2) we're
-                # in the middle of a request.
-                # See http://www.cherrypy.org/ticket/853
-                if (not request_seen) or (req and req.started_request):
-                    # Don't bother writing the 408 if the response
-                    # has already started being written.
-                    if req and not req.sent_headers:
-                        try:
-                            req.simple_response("408 Request Timeout")
-                        except FatalSSLAlert:
-                            # Close the connection.
-                            return
-            elif errnum not in socket_errors_to_ignore:
-                if req and not req.sent_headers:
-                    try:
-                        req.simple_response("500 Internal Server Error",
-                                            format_exc())
-                    except FatalSSLAlert:
-                        # Close the connection.
-                        return
-            return
-        except (KeyboardInterrupt, SystemExit):
-            raise
-        except FatalSSLAlert:
-            # Close the connection.
-            return
-        except NoSSLError:
-            if req and not req.sent_headers:
-                # Unwrap our wfile
-                self.wfile = CP_fileobject(self.socket._sock, "wb", -1)
-                req.simple_response("400 Bad Request",
-                    "The client sent a plain HTTP request, but "
-                    "this server only speaks HTTPS on this port.")
-                self.linger = True
-        except Exception:
-            if req and not req.sent_headers:
-                try:
-                    req.simple_response("500 Internal Server Error", format_exc())
-                except FatalSSLAlert:
-                    # Close the connection.
-                    return
-    
-    linger = False
-    
-    def close(self):
-        """Close the socket underlying this connection."""
-        self.rfile.close()
-        
-        if not self.linger:
-            # Python's socket module does NOT call close on the kernel socket
-            # when you call socket.close(). We do so manually here because we
-            # want this server to send a FIN TCP segment immediately. Note this
-            # must be called *before* calling socket.close(), because the latter
-            # drops its reference to the kernel socket.
-            if hasattr(self.socket, '_sock'):
-                self.socket._sock.close()
-            self.socket.close()
-        else:
-            # On the other hand, sometimes we want to hang around for a bit
-            # to make sure the client has a chance to read our entire
-            # response. Skipping the close() calls here delays the FIN
-            # packet until the socket object is garbage-collected later.
-            # Someday, perhaps, we'll do the full lingering_close that
-            # Apache does, but not today.
-            pass
-
-
-def format_exc(limit=None):
-    """Like print_exc() but return a string. Backport for Python 2.3."""
-    try:
-        etype, value, tb = sys.exc_info()
-        return ''.join(traceback.format_exception(etype, value, tb, limit))
-    finally:
-        etype = value = tb = None
-
-
-_SHUTDOWNREQUEST = None
-
-class WorkerThread(threading.Thread):
-    """Thread which continuously polls a Queue for Connection objects.
-    
-    server: the HTTP Server which spawned this thread, and which owns the
-        Queue and is placing active connections into it.
-    ready: a simple flag for the calling server to know when this thread
-        has begun polling the Queue.
-    
-    Due to the timing issues of polling a Queue, a WorkerThread does not
-    check its own 'ready' flag after it has started. To stop the thread,
-    it is necessary to stick a _SHUTDOWNREQUEST object onto the Queue
-    (one for each running WorkerThread).
-    """
-    
-    conn = None
-    
-    def __init__(self, server):
-        self.ready = False
-        self.server = server
-        threading.Thread.__init__(self)
-    
-    def run(self):
-        try:
-            self.ready = True
-            while True:
-                conn = self.server.requests.get()
-                if conn is _SHUTDOWNREQUEST:
-                    return
-                
-                self.conn = conn
-                try:
-                    conn.communicate()
-                finally:
-                    conn.close()
-                    self.conn = None
-        except (KeyboardInterrupt, SystemExit), exc:
-            self.server.interrupt = exc
-
-
-class ThreadPool(object):
-    """A Request Queue for the CherryPyWSGIServer which pools threads.
-    
-    ThreadPool objects must provide min, get(), put(obj), start()
-    and stop(timeout) attributes.
-    """
-    
-    def __init__(self, server, min=10, max=-1):
-        self.server = server
-        self.min = min
-        self.max = max
-        self._threads = []
-        self._queue = Queue.Queue()
-        self.get = self._queue.get
-    
-    def start(self):
-        """Start the pool of threads."""
-        for i in range(self.min):
-            self._threads.append(WorkerThread(self.server))
-        for worker in self._threads:
-            worker.setName("CP Server " + worker.getName())
-            worker.start()
-        for worker in self._threads:
-            while not worker.ready:
-                time.sleep(.1)
-    
-    def _get_idle(self):
-        """Number of worker threads which are idle. Read-only."""
-        return len([t for t in self._threads if t.conn is None])
-    idle = property(_get_idle, doc=_get_idle.__doc__)
-    
-    def put(self, obj):
-        self._queue.put(obj)
-        if obj is _SHUTDOWNREQUEST:
-            return
-    
-    def grow(self, amount):
-        """Spawn new worker threads (not above self.max)."""
-        for i in range(amount):
-            if self.max > 0 and len(self._threads) >= self.max:
-                break
-            worker = WorkerThread(self.server)
-            worker.setName("CP Server " + worker.getName())
-            self._threads.append(worker)
-            worker.start()
-    
-    def shrink(self, amount):
-        """Kill off worker threads (not below self.min)."""
-        # Grow/shrink the pool if necessary.
-        # Remove any dead threads from our list
-        for t in self._threads:
-            if not t.isAlive():
-                self._threads.remove(t)
-                amount -= 1
-        
-        if amount > 0:
-            for i in range(min(amount, len(self._threads) - self.min)):
-                # Put a number of shutdown requests on the queue equal
-                # to 'amount'. Once each of those is processed by a worker,
-                # that worker will terminate and be culled from our list
-                # in self.put.
-                self._queue.put(_SHUTDOWNREQUEST)
-    
-    def stop(self, timeout=5):
-        # Must shut down threads here so the code that calls
-        # this method can know when all threads are stopped.
-        for worker in self._threads:
-            self._queue.put(_SHUTDOWNREQUEST)
-        
-        # Don't join currentThread (when stop is called inside a request).
-        current = threading.currentThread()
-        if timeout and timeout >= 0:
-            endtime = time.time() + timeout
-        while self._threads:
-            worker = self._threads.pop()
-            if worker is not current and worker.isAlive():
-                try:
-                    if timeout is None or timeout < 0:
-                        worker.join()
-                    else:
-                        remaining_time = endtime - time.time()
-                        if remaining_time > 0:
-                            worker.join(remaining_time)
-                        if worker.isAlive():
-                            # We exhausted the timeout.
-                            # Forcibly shut down the socket.
-                            c = worker.conn
-                            if c and not c.rfile.closed:
-                                try:
-                                    c.socket.shutdown(socket.SHUT_RD)
-                                except TypeError:
-                                    # pyOpenSSL sockets don't take an arg
-                                    c.socket.shutdown()
-                            worker.join()
-                except (AssertionError,
-                        # Ignore repeated Ctrl-C.
-                        # See http://www.cherrypy.org/ticket/691.
-                        KeyboardInterrupt), exc1:
-                    pass
-
-
-
-try:
-    import fcntl
-except ImportError:
-    try:
-        from ctypes import windll, WinError
-    except ImportError:
-        def prevent_socket_inheritance(sock):
-            """Dummy function, since neither fcntl nor ctypes are available."""
-            pass
-    else:
-        def prevent_socket_inheritance(sock):
-            """Mark the given socket fd as non-inheritable (Windows)."""
-            if not windll.kernel32.SetHandleInformation(sock.fileno(), 1, 0):
-                raise WinError()
-else:
-    def prevent_socket_inheritance(sock):
-        """Mark the given socket fd as non-inheritable (POSIX)."""
-        fd = sock.fileno()
-        old_flags = fcntl.fcntl(fd, fcntl.F_GETFD)
-        fcntl.fcntl(fd, fcntl.F_SETFD, old_flags | fcntl.FD_CLOEXEC)
-
-
-class SSLAdapter(object):
-    
-    def __init__(self, certificate, private_key, certificate_chain=None):
-        self.certificate = certificate
-        self.private_key = private_key
-        self.certificate_chain = certificate_chain
-    
-    def wrap(self, sock):
-        raise NotImplemented
-    
-    def makefile(self, sock, mode='r', bufsize=-1):
-        raise NotImplemented
-
-
-class HTTPServer(object):
-    """An HTTP server.
-    
-    bind_addr: The interface on which to listen for connections.
-        For TCP sockets, a (host, port) tuple. Host values may be any IPv4
-        or IPv6 address, or any valid hostname. The string 'localhost' is a
-        synonym for '127.0.0.1' (or '::1', if your hosts file prefers IPv6).
-        The string '0.0.0.0' is a special IPv4 entry meaning "any active
-        interface" (INADDR_ANY), and '::' is the similar IN6ADDR_ANY for
-        IPv6. The empty string or None are not allowed.
-        
-        For UNIX sockets, supply the filename as a string.
-    gateway: a Gateway instance.
-    minthreads: the minimum number of worker threads to create (default 10).
-    maxthreads: the maximum number of worker threads to create (default -1 = no limit).
-    server_name: defaults to socket.gethostname().
-    
-    request_queue_size: the 'backlog' argument to socket.listen();
-        specifies the maximum number of queued connections (default 5).
-    timeout: the timeout in seconds for accepted connections (default 10).
-    nodelay: if True (the default since 3.1), sets the TCP_NODELAY socket
-        option.
-    protocol: the version string to write in the Status-Line of all
-        HTTP responses. For example, "HTTP/1.1" (the default). This
-        also limits the supported features used in the response.
-    
-    
-    SSL/HTTPS
-    ---------
-    You must have an ssl library installed and set self.ssl_adapter to an
-    instance of SSLAdapter (or a subclass) which provides the methods:
-        wrap(sock) -> wrapped socket, ssl environ dict
-        makefile(sock, mode='r', bufsize=-1) -> socket file object
-    """
-    
-    protocol = "HTTP/1.1"
-    _bind_addr = "127.0.0.1"
-    version = "CherryPy/3.2.0rc1"
-    response_header = None
-    ready = False
-    _interrupt = None
-    max_request_header_size = 0
-    max_request_body_size = 0
-    nodelay = True
-    
-    ConnectionClass = HTTPConnection
-    
-    ssl_adapter = None
-    
-    def __init__(self, bind_addr, gateway, minthreads=10, maxthreads=-1,
-                 server_name=None):
-        self.bind_addr = bind_addr
-        self.gateway = gateway
-        
-        self.requests = ThreadPool(self, min=minthreads or 1, max=maxthreads)
-        
-        if not server_name:
-            server_name = socket.gethostname()
-        self.server_name = server_name
-    
-    def __str__(self):
-        return "%s.%s(%r)" % (self.__module__, self.__class__.__name__,
-                              self.bind_addr)
-    
-    def _get_bind_addr(self):
-        return self._bind_addr
-    def _set_bind_addr(self, value):
-        if isinstance(value, tuple) and value[0] in ('', None):
-            # Despite the socket module docs, using '' does not
-            # allow AI_PASSIVE to work. Passing None instead
-            # returns '0.0.0.0' like we want. In other words:
-            #     host    AI_PASSIVE     result
-            #      ''         Y         192.168.x.y
-            #      ''         N         192.168.x.y
-            #     None        Y         0.0.0.0
-            #     None        N         127.0.0.1
-            # But since you can get the same effect with an explicit
-            # '0.0.0.0', we deny both the empty string and None as values.
-            raise ValueError("Host values of '' or None are not allowed. "
-                             "Use '0.0.0.0' (IPv4) or '::' (IPv6) instead "
-                             "to listen on all active interfaces.")
-        self._bind_addr = value
-    bind_addr = property(_get_bind_addr, _set_bind_addr,
-        doc="""The interface on which to listen for connections.
-        
-        For TCP sockets, a (host, port) tuple. Host values may be any IPv4
-        or IPv6 address, or any valid hostname. The string 'localhost' is a
-        synonym for '127.0.0.1' (or '::1', if your hosts file prefers IPv6).
-        The string '0.0.0.0' is a special IPv4 entry meaning "any active
-        interface" (INADDR_ANY), and '::' is the similar IN6ADDR_ANY for
-        IPv6. The empty string or None are not allowed.
-        
-        For UNIX sockets, supply the filename as a string.""")
-    
-    def start(self):
-        """Run the server forever."""
-        # We don't have to trap KeyboardInterrupt or SystemExit here,
-        # because cherrpy.server already does so, calling self.stop() for us.
-        # If you're using this server with another framework, you should
-        # trap those exceptions in whatever code block calls start().
-        self._interrupt = None
-        
-        # SSL backward compatibility
-        if (self.ssl_adapter is None and
-            getattr(self, 'ssl_certificate', None) and
-            getattr(self, 'ssl_private_key', None)):
-            warnings.warn(
-                    "SSL attributes are deprecated in CherryPy 3.2, and will "
-                    "be removed in CherryPy 3.3. Use an ssl_adapter attribute "
-                    "instead.",
-                    DeprecationWarning
-                )
-            try:
-                from cherrypy.wsgiserver.ssl_pyopenssl import pyOpenSSLAdapter
-            except ImportError:
-                pass
-            else:
-                self.ssl_adapter = pyOpenSSLAdapter(
-                    self.ssl_certificate, self.ssl_private_key,
-                    getattr(self, 'ssl_certificate_chain', None))
-        
-        # Select the appropriate socket
-        if isinstance(self.bind_addr, basestring):
-            # AF_UNIX socket
-            
-            # So we can reuse the socket...
-            try: os.unlink(self.bind_addr)
-            except: pass
-            
-            # So everyone can access the socket...
-            try: os.chmod(self.bind_addr, 0777)
-            except: pass
-            
-            info = [(socket.AF_UNIX, socket.SOCK_STREAM, 0, "", self.bind_addr)]
-        else:
-            # AF_INET or AF_INET6 socket
-            # Get the correct address family for our host (allows IPv6 addresses)
-            host, port = self.bind_addr
-            try:
-                info = socket.getaddrinfo(host, port, socket.AF_UNSPEC,
-                                          socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
-            except socket.gaierror:
-                if ':' in self.bind_addr[0]:
-                    info = [(socket.AF_INET6, socket.SOCK_STREAM,
-                             0, "", self.bind_addr + (0, 0))]
-                else:
-                    info = [(socket.AF_INET, socket.SOCK_STREAM,
-                             0, "", self.bind_addr)]
-        
-        self.socket = None
-        msg = "No socket could be created"
-        for res in info:
-            af, socktype, proto, canonname, sa = res
-            try:
-                self.bind(af, socktype, proto)
-            except socket.error, msg:
-                if self.socket:
-                    self.socket.close()
-                self.socket = None
-                continue
-            break
-        if not self.socket:
-            raise socket.error(msg)
-        
-        # Timeout so KeyboardInterrupt can be caught on Win32
-        self.socket.settimeout(1)
-        self.socket.listen(self.request_queue_size)
-        
-        # Create worker threads
-        self.requests.start()
-        
-        self.ready = True
-        while self.ready:
-            self.tick()
-            if self.interrupt:
-                while self.interrupt is True:
-                    # Wait for self.stop() to complete. See _set_interrupt.
-                    time.sleep(0.1)
-                if self.interrupt:
-                    raise self.interrupt
-    
-    def bind(self, family, type, proto=0):
-        """Create (or recreate) the actual socket object."""
-        self.socket = socket.socket(family, type, proto)
-        prevent_socket_inheritance(self.socket)
-        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-        if self.nodelay and not isinstance(self.bind_addr, str):
-            self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
-        
-        if self.ssl_adapter is not None:
-            self.socket = self.ssl_adapter.bind(self.socket)
-        
-        # If listening on the IPV6 any address ('::' = IN6ADDR_ANY),
-        # activate dual-stack. See http://www.cherrypy.org/ticket/871.
-        if (family == socket.AF_INET6
-            and self.bind_addr[0] in ('::', '::0', '::0.0.0.0')):
-            try:
-                self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
-            except (AttributeError, socket.error):
-                # Apparently, the socket option is not available in
-                # this machine's TCP stack
-                pass
-        
-        self.socket.bind(self.bind_addr)
-    
-    def tick(self):
-        """Accept a new connection and put it on the Queue."""
-        try:
-            s, addr = self.socket.accept()
-            if not self.ready:
-                return
-            
-            prevent_socket_inheritance(s)
-            if hasattr(s, 'settimeout'):
-                s.settimeout(self.timeout)
-            
-            if self.response_header is None:
-                self.response_header = "%s Server" % self.version
-            
-            makefile = CP_fileobject
-            ssl_env = {}
-            # if ssl cert and key are set, we try to be a secure HTTP server
-            if self.ssl_adapter is not None:
-                try:
-                    s, ssl_env = self.ssl_adapter.wrap(s)
-                except NoSSLError:
-                    msg = ("The client sent a plain HTTP request, but "
-                           "this server only speaks HTTPS on this port.")
-                    buf = ["%s 400 Bad Request\r\n" % self.protocol,
-                           "Content-Length: %s\r\n" % len(msg),
-                           "Content-Type: text/plain\r\n\r\n",
-                           msg]
-                    
-                    wfile = CP_fileobject(s, "wb", -1)
-                    try:
-                        wfile.sendall("".join(buf))
-                    except socket.error, x:
-                        if x.args[0] not in socket_errors_to_ignore:
-                            raise
-                    return
-                if not s:
-                    return
-                makefile = self.ssl_adapter.makefile
-            
-            conn = self.ConnectionClass(self, s, makefile)
-            
-            if not isinstance(self.bind_addr, basestring):
-                # optional values
-                # Until we do DNS lookups, omit REMOTE_HOST
-                if addr is None: # sometimes this can happen
-                    # figure out if AF_INET or AF_INET6.
-                    if len(s.getsockname()) == 2:
-                        # AF_INET
-                        addr = ('0.0.0.0', 0)
-                    else:
-                        # AF_INET6
-                        addr = ('::', 0)
-                conn.remote_addr = addr[0]
-                conn.remote_port = addr[1]
-            
-            conn.ssl_env = ssl_env
-            
-            self.requests.put(conn)
-        except socket.timeout:
-            # The only reason for the timeout in start() is so we can
-            # notice keyboard interrupts on Win32, which don't interrupt
-            # accept() by default
-            return
-        except socket.error, x:
-            if x.args[0] in socket_error_eintr:
-                # I *think* this is right. EINTR should occur when a signal
-                # is received during the accept() call; all docs say retry
-                # the call, and I *think* I'm reading it right that Python
-                # will then go ahead and poll for and handle the signal
-                # elsewhere. See http://www.cherrypy.org/ticket/707.
-                return
-            if x.args[0] in socket_errors_nonblocking:
-                # Just try again. See http://www.cherrypy.org/ticket/479.
-                return
-            if x.args[0] in socket_errors_to_ignore:
-                # Our socket was closed.
-                # See http://www.cherrypy.org/ticket/686.
-                return
-            raise
-    
-    def _get_interrupt(self):
-        return self._interrupt
-    def _set_interrupt(self, interrupt):
-        self._interrupt = True
-        self.stop()
-        self._interrupt = interrupt
-    interrupt = property(_get_interrupt, _set_interrupt,
-                         doc="Set this to an Exception instance to "
-                             "interrupt the server.")
-    
-    def stop(self):
-        """Gracefully shutdown a server that is serving forever."""
-        self.ready = False
-        
-        sock = getattr(self, "socket", None)
-        if sock:
-            if not isinstance(self.bind_addr, basestring):
-                # Touch our own socket to make accept() return immediately.
-                try:
-                    host, port = sock.getsockname()[:2]
-                except socket.error, x:
-                    if x.args[0] not in socket_errors_to_ignore:
-                        # Changed to use error code and not message
-                        # See http://www.cherrypy.org/ticket/860.
-                        raise
-                else:
-                    # Note that we're explicitly NOT using AI_PASSIVE,
-                    # here, because we want an actual IP to touch.
-                    # localhost won't work if we've bound to a public IP,
-                    # but it will if we bound to '0.0.0.0' (INADDR_ANY).
-                    for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC,
-                                                  socket.SOCK_STREAM):
-                        af, socktype, proto, canonname, sa = res
-                        s = None
-                        try:
-                            s = socket.socket(af, socktype, proto)
-                            # See http://groups.google.com/group/cherrypy-users/
-                            #        browse_frm/thread/bbfe5eb39c904fe0
-                            s.settimeout(1.0)
-                            s.connect((host, port))
-                            s.close()
-                        except socket.error:
-                            if s:
-                                s.close()
-            if hasattr(sock, "close"):
-                sock.close()
-            self.socket = None
-        
-        self.requests.stop(self.shutdown_timeout)
-
-
-class Gateway(object):
-    
-    def __init__(self, req):
-        self.req = req
-    
-    def respond(self):
-        raise NotImplemented
-
-
-# These may either be wsgiserver.SSLAdapter subclasses or the string names
-# of such classes (in which case they will be lazily loaded).
-ssl_adapters = {
-    'builtin': 'cherrypy.wsgiserver.ssl_builtin.BuiltinSSLAdapter',
-    'pyopenssl': 'cherrypy.wsgiserver.ssl_pyopenssl.pyOpenSSLAdapter',
-    }
-
-def get_ssl_adapter_class(name='pyopenssl'):
-    adapter = ssl_adapters[name.lower()]
-    if isinstance(adapter, basestring):
-        last_dot = adapter.rfind(".")
-        attr_name = adapter[last_dot + 1:]
-        mod_path = adapter[:last_dot]
-        
-        try:
-            mod = sys.modules[mod_path]
-            if mod is None:
-                raise KeyError()
-        except KeyError:
-            # The last [''] is important.
-            mod = __import__(mod_path, globals(), locals(), [''])
-        
-        # Let an AttributeError propagate outward.
-        try:
-            adapter = getattr(mod, attr_name)
-        except AttributeError:
-            raise AttributeError("'%s' object has no attribute '%s'"
-                                 % (mod_path, attr_name))
-    
-    return adapter
-
-# -------------------------------- WSGI Stuff -------------------------------- #
-
-
-class CherryPyWSGIServer(HTTPServer):
-    
-    wsgi_version = (1, 1)
-    
-    def __init__(self, bind_addr, wsgi_app, numthreads=10, server_name=None,
-                 max=-1, request_queue_size=5, timeout=10, shutdown_timeout=5):
-        self.requests = ThreadPool(self, min=numthreads or 1, max=max)
-        self.wsgi_app = wsgi_app
-        self.gateway = wsgi_gateways[self.wsgi_version]
-        
-        self.bind_addr = bind_addr
-        if not server_name:
-            server_name = socket.gethostname()
-        self.server_name = server_name
-        self.request_queue_size = request_queue_size
-        
-        self.timeout = timeout
-        self.shutdown_timeout = shutdown_timeout
-    
-    def _get_numthreads(self):
-        return self.requests.min
-    def _set_numthreads(self, value):
-        self.requests.min = value
-    numthreads = property(_get_numthreads, _set_numthreads)
-
-
-class WSGIGateway(Gateway):
-    
-    def __init__(self, req):
-        self.req = req
-        self.started_response = False
-        self.env = self.get_environ()
-    
-    def get_environ(self):
-        """Return a new environ dict targeting the given wsgi.version"""
-        raise NotImplemented
-    
-    def respond(self):
-        response = self.req.server.wsgi_app(self.env, self.start_response)
-        try:
-            for chunk in response:
-                # "The start_response callable must not actually transmit
-                # the response headers. Instead, it must store them for the
-                # server or gateway to transmit only after the first
-                # iteration of the application return value that yields
-                # a NON-EMPTY string, or upon the application's first
-                # invocation of the write() callable." (PEP 333)
-                if chunk:
-                    if isinstance(chunk, unicode):
-                        chunk = chunk.encode('ISO-8859-1')
-                    self.write(chunk)
-        finally:
-            if hasattr(response, "close"):
-                response.close()
-    
-    def start_response(self, status, headers, exc_info = None):
-        """WSGI callable to begin the HTTP response."""
-        # "The application may call start_response more than once,
-        # if and only if the exc_info argument is provided."
-        if self.started_response and not exc_info:
-            raise AssertionError("WSGI start_response called a second "
-                                 "time with no exc_info.")
-        self.started_response = True
-        
-        # "if exc_info is provided, and the HTTP headers have already been
-        # sent, start_response must raise an error, and should raise the
-        # exc_info tuple."
-        if self.req.sent_headers:
-            try:
-                raise exc_info[0], exc_info[1], exc_info[2]
-            finally:
-                exc_info = None
-        
-        self.req.status = status
-        for k, v in headers:
-            if not isinstance(k, str):
-                raise TypeError("WSGI response header key %r is not a byte string." % k)
-            if not isinstance(v, str):
-                raise TypeError("WSGI response header value %r is not a byte string." % v)
-        self.req.outheaders.extend(headers)
-        
-        return self.write
-    
-    def write(self, chunk):
-        """WSGI callable to write unbuffered data to the client.
-        
-        This method is also used internally by start_response (to write
-        data from the iterable returned by the WSGI application).
-        """
-        if not self.started_response:
-            raise AssertionError("WSGI write called before start_response.")
-        
-        if not self.req.sent_headers:
-            self.req.sent_headers = True
-            self.req.send_headers()
-        
-        self.req.write(chunk)
-
-
-class WSGIGateway_10(WSGIGateway):
-    
-    def get_environ(self):
-        """Return a new environ dict targeting the given wsgi.version"""
-        req = self.req
-        env = {
-            # set a non-standard environ entry so the WSGI app can know what
-            # the *real* server protocol is (and what features to support).
-            # See http://www.faqs.org/rfcs/rfc2145.html.
-            'ACTUAL_SERVER_PROTOCOL': req.server.protocol,
-            'PATH_INFO': req.path,
-            'QUERY_STRING': req.qs,
-            'REMOTE_ADDR': req.conn.remote_addr or '',
-            'REMOTE_PORT': str(req.conn.remote_port or ''),
-            'REQUEST_METHOD': req.method,
-            'REQUEST_URI': req.uri,
-            'SCRIPT_NAME': '',
-            'SERVER_NAME': req.server.server_name,
-            # Bah. "SERVER_PROTOCOL" is actually the REQUEST protocol.
-            'SERVER_PROTOCOL': req.request_protocol,
-            'wsgi.errors': sys.stderr,
-            'wsgi.input': req.rfile,
-            'wsgi.multiprocess': False,
-            'wsgi.multithread': True,
-            'wsgi.run_once': False,
-            'wsgi.url_scheme': req.scheme,
-            'wsgi.version': (1, 0),
-            }
-        
-        if isinstance(req.server.bind_addr, basestring):
-            # AF_UNIX. This isn't really allowed by WSGI, which doesn't
-            # address unix domain sockets. But it's better than nothing.
-            env["SERVER_PORT"] = ""
-        else:
-            env["SERVER_PORT"] = str(req.server.bind_addr[1])
-        
-        # CONTENT_TYPE/CONTENT_LENGTH
-        for k, v in req.inheaders.iteritems():
-            env["HTTP_" + k.upper().replace("-", "_")] = v
-        ct = env.pop("HTTP_CONTENT_TYPE", None)
-        if ct is not None:
-            env["CONTENT_TYPE"] = ct
-        cl = env.pop("HTTP_CONTENT_LENGTH", None)
-        if cl is not None:
-            env["CONTENT_LENGTH"] = cl
-        
-        if req.conn.ssl_env:
-            env.update(req.conn.ssl_env)
-        
-        return env
-
-
-class WSGIGateway_11(WSGIGateway_10):
-    
-    def get_environ(self):
-        env = WSGIGateway_10.get_environ(self)
-        env['wsgi.version'] = (1, 1)
-        return env
-
-
-class WSGIGateway_u0(WSGIGateway_10):
-    
-    def get_environ(self):
-        """Return a new environ dict targeting the given wsgi.version"""
-        req = self.req
-        env_10 = WSGIGateway_10.get_environ(self)
-        env = dict([(k.decode('ISO-8859-1'), v) for k, v in env_10.iteritems()])
-        env[u'wsgi.version'] = ('u', 0)
-        
-        # Request-URI
-        env.setdefault(u'wsgi.url_encoding', u'utf-8')
-        try:
-            for key in [u"PATH_INFO", u"SCRIPT_NAME", u"QUERY_STRING"]:
-                env[key] = env_10[str(key)].decode(env[u'wsgi.url_encoding'])
-        except UnicodeDecodeError:
-            # Fall back to latin 1 so apps can transcode if needed.
-            env[u'wsgi.url_encoding'] = u'ISO-8859-1'
-            for key in [u"PATH_INFO", u"SCRIPT_NAME", u"QUERY_STRING"]:
-                env[key] = env_10[str(key)].decode(env[u'wsgi.url_encoding'])
-        
-        for k, v in sorted(env.items()):
-            if isinstance(v, str) and k not in ('REQUEST_URI', 'wsgi.input'):
-                env[k] = v.decode('ISO-8859-1')
-        
-        return env
-
-wsgi_gateways = {
-    (1, 0): WSGIGateway_10,
-    (1, 1): WSGIGateway_11,
-    ('u', 0): WSGIGateway_u0,
-}
-
-class WSGIPathInfoDispatcher(object):
-    """A WSGI dispatcher for dispatch based on the PATH_INFO.
-    
-    apps: a dict or list of (path_prefix, app) pairs.
-    """
-    
-    def __init__(self, apps):
-        try:
-            apps = apps.items()
-        except AttributeError:
-            pass
-        
-        # Sort the apps by len(path), descending
-        apps.sort(cmp=lambda x,y: cmp(len(x[0]), len(y[0])))
-        apps.reverse()
-        
-        # The path_prefix strings must start, but not end, with a slash.
-        # Use "" instead of "/".
-        self.apps = [(p.rstrip("/"), a) for p, a in apps]
-    
-    def __call__(self, environ, start_response):
-        path = environ["PATH_INFO"] or "/"
-        for p, app in self.apps:
-            # The apps list should be sorted by length, descending.
-            if path.startswith(p + "/") or path == p:
-                environ = environ.copy()
-                environ["SCRIPT_NAME"] = environ["SCRIPT_NAME"] + p
-                environ["PATH_INFO"] = path[len(p):]
-                return app(environ, start_response)
-        
-        start_response('404 Not Found', [('Content-Type', 'text/plain'),
-                                         ('Content-Length', '0')])
-        return ['']
--- a/bundled/cherrypy/cherrypy/wsgiserver/ssl_builtin.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-"""A library for integrating pyOpenSSL with CherryPy.
-
-The ssl module must be importable for SSL functionality.
-
-To use this module, set CherryPyWSGIServer.ssl_adapter to an instance of
-BuiltinSSLAdapter.
-
-    ssl_adapter.certificate: the filename of the server SSL certificate.
-    ssl_adapter.private_key: the filename of the server's private key file.
-"""
-
-try:
-    import ssl
-except ImportError:
-    ssl = None
-
-from cherrypy import wsgiserver
-
-
-class BuiltinSSLAdapter(wsgiserver.SSLAdapter):
-    """A wrapper for integrating Python's builtin ssl module with CherryPy."""
-    
-    def __init__(self, certificate, private_key, certificate_chain=None):
-        if ssl is None:
-            raise ImportError("You must install the ssl module to use HTTPS.")
-        self.certificate = certificate
-        self.private_key = private_key
-        self.certificate_chain = certificate_chain
-    
-    def bind(self, sock):
-        """Wrap and return the given socket."""
-        return sock
-    
-    def wrap(self, sock):
-        """Wrap and return the given socket, plus WSGI environ entries."""
-        try:
-            s = ssl.wrap_socket(sock, do_handshake_on_connect=True,
-                    server_side=True, certfile=self.certificate,
-                    keyfile=self.private_key, ssl_version=ssl.PROTOCOL_SSLv23)
-        except ssl.SSLError, e:
-            if e.errno == ssl.SSL_ERROR_EOF:
-                # This is almost certainly due to the cherrypy engine
-                # 'pinging' the socket to assert it's connectable;
-                # the 'ping' isn't SSL.
-                return None, {}
-            elif e.errno == ssl.SSL_ERROR_SSL:
-                if e.args[1].endswith('http request'):
-                    # The client is speaking HTTP to an HTTPS server.
-                    raise wsgiserver.NoSSLError
-            raise
-        return s, self.get_environ(s)
-    
-    # TODO: fill this out more with mod ssl env
-    def get_environ(self, sock):
-        """Create WSGI environ entries to be merged into each request."""
-        cipher = sock.cipher()
-        ssl_environ = {
-            "wsgi.url_scheme": "https",
-            "HTTPS": "on",
-            'SSL_PROTOCOL': cipher[1],
-            'SSL_CIPHER': cipher[0]
-##            SSL_VERSION_INTERFACE 	string 	The mod_ssl program version
-##            SSL_VERSION_LIBRARY 	string 	The OpenSSL program version
-            }
-        return ssl_environ
-    
-    def makefile(self, sock, mode='r', bufsize=-1):
-        return wsgiserver.CP_fileobject(sock, mode, bufsize)
-
--- a/bundled/cherrypy/cherrypy/wsgiserver/ssl_pyopenssl.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,241 +0,0 @@
-"""A library for integrating pyOpenSSL with CherryPy.
-
-The OpenSSL module must be importable for SSL functionality.
-You can obtain it from http://pyopenssl.sourceforge.net/
-
-To use this module, set CherryPyWSGIServer.ssl_adapter to an instance of
-SSLAdapter. There are two ways to use SSL:
-
-Method One:
-    ssl_adapter.context: an instance of SSL.Context.
-    
-    If this is not None, it is assumed to be an SSL.Context instance,
-    and will be passed to SSL.Connection on bind(). The developer is
-    responsible for forming a valid Context object. This approach is
-    to be preferred for more flexibility, e.g. if the cert and key are
-    streams instead of files, or need decryption, or SSL.SSLv3_METHOD
-    is desired instead of the default SSL.SSLv23_METHOD, etc. Consult
-    the pyOpenSSL documentation for complete options.
-
-Method Two (shortcut):
-    ssl_adapter.certificate: the filename of the server SSL certificate.
-    ssl_adapter.private_key: the filename of the server's private key file.
-    
-    Both are None by default. If ssl_adapter.context is None, but .private_key
-    and .certificate are both given and valid, they will be read, and the
-    context will be automatically created from them.
-    
-    ssl_adapter.certificate_chain: (optional) the filename of CA's intermediate
-        certificate bundle. This is needed for cheaper "chained root" SSL
-        certificates, and should be left as None if not required.
-"""
-
-import socket
-import threading
-import time
-
-from cherrypy import wsgiserver
-
-try:
-    from OpenSSL import SSL
-    from OpenSSL import crypto
-except ImportError:
-    SSL = None
-
-
-class SSL_fileobject(wsgiserver.CP_fileobject):
-    """SSL file object attached to a socket object."""
-    
-    ssl_timeout = 3
-    ssl_retry = .01
-    
-    def _safe_call(self, is_reader, call, *args, **kwargs):
-        """Wrap the given call with SSL error-trapping.
-        
-        is_reader: if False EOF errors will be raised. If True, EOF errors
-            will return "" (to emulate normal sockets).
-        """
-        start = time.time()
-        while True:
-            try:
-                return call(*args, **kwargs)
-            except SSL.WantReadError:
-                # Sleep and try again. This is dangerous, because it means
-                # the rest of the stack has no way of differentiating
-                # between a "new handshake" error and "client dropped".
-                # Note this isn't an endless loop: there's a timeout below.
-                time.sleep(self.ssl_retry)
-            except SSL.WantWriteError:
-                time.sleep(self.ssl_retry)
-            except SSL.SysCallError, e:
-                if is_reader and e.args == (-1, 'Unexpected EOF'):
-                    return ""
-                
-                errnum = e.args[0]
-                if is_reader and errnum in wsgiserver.socket_errors_to_ignore:
-                    return ""
-                raise socket.error(errnum)
-            except SSL.Error, e:
-                if is_reader and e.args == (-1, 'Unexpected EOF'):
-                    return ""
-                
-                thirdarg = None
-                try:
-                    thirdarg = e.args[0][0][2]
-                except IndexError:
-                    pass
-                
-                if thirdarg == 'http request':
-                    # The client is talking HTTP to an HTTPS server.
-                    raise wsgiserver.NoSSLError()
-                
-                raise wsgiserver.FatalSSLAlert(*e.args)
-            except:
-                raise
-            
-            if time.time() - start > self.ssl_timeout:
-                raise socket.timeout("timed out")
-    
-    def recv(self, *args, **kwargs):
-        buf = []
-        r = super(SSL_fileobject, self).recv
-        while True:
-            data = self._safe_call(True, r, *args, **kwargs)
-            buf.append(data)
-            p = self._sock.pending()
-            if not p:
-                return "".join(buf)
-    
-    def sendall(self, *args, **kwargs):
-        return self._safe_call(False, super(SSL_fileobject, self).sendall,
-                               *args, **kwargs)
-
-    def send(self, *args, **kwargs):
-        return self._safe_call(False, super(SSL_fileobject, self).send,
-                               *args, **kwargs)
-
-
-class SSLConnection:
-    """A thread-safe wrapper for an SSL.Connection.
-    
-    *args: the arguments to create the wrapped SSL.Connection(*args).
-    """
-    
-    def __init__(self, *args):
-        self._ssl_conn = SSL.Connection(*args)
-        self._lock = threading.RLock()
-    
-    for f in ('get_context', 'pending', 'send', 'write', 'recv', 'read',
-              'renegotiate', 'bind', 'listen', 'connect', 'accept',
-              'setblocking', 'fileno', 'close', 'get_cipher_list',
-              'getpeername', 'getsockname', 'getsockopt', 'setsockopt',
-              'makefile', 'get_app_data', 'set_app_data', 'state_string',
-              'sock_shutdown', 'get_peer_certificate', 'want_read',
-              'want_write', 'set_connect_state', 'set_accept_state',
-              'connect_ex', 'sendall', 'settimeout', 'gettimeout'):
-        exec("""def %s(self, *args):
-        self._lock.acquire()
-        try:
-            return self._ssl_conn.%s(*args)
-        finally:
-            self._lock.release()
-""" % (f, f))
-    
-    def shutdown(self, *args):
-        self._lock.acquire()
-        try:
-            # pyOpenSSL.socket.shutdown takes no args
-            return self._ssl_conn.shutdown()
-        finally:
-            self._lock.release()
-
-
-class pyOpenSSLAdapter(wsgiserver.SSLAdapter):
-    """A wrapper for integrating pyOpenSSL with CherryPy."""
-    
-    def __init__(self, certificate, private_key, certificate_chain=None):
-        if SSL is None:
-            raise ImportError("You must install pyOpenSSL to use HTTPS.")
-        
-        self.context = None
-        self.certificate = certificate
-        self.private_key = private_key
-        self.certificate_chain = certificate_chain
-        self._environ = None
-    
-    def bind(self, sock):
-        """Wrap and return the given socket."""
-        if self.context is None:
-            self.context = self.get_context()
-        conn = SSLConnection(self.context, sock)
-        self._environ = self.get_environ()
-        return conn
-    
-    def wrap(self, sock):
-        """Wrap and return the given socket, plus WSGI environ entries."""
-        return sock, self._environ.copy()
-    
-    def get_context(self):
-        """Return an SSL.Context from self attributes."""
-        # See http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/442473
-        c = SSL.Context(SSL.SSLv23_METHOD)
-        c.use_privatekey_file(self.private_key)
-        if self.certificate_chain:
-            c.load_verify_locations(self.certificate_chain)
-        c.use_certificate_file(self.certificate)
-        return c
-    
-    def get_environ(self):
-        """Return WSGI environ entries to be merged into each request."""
-        ssl_environ = {
-            "HTTPS": "on",
-            # pyOpenSSL doesn't provide access to any of these AFAICT
-##            'SSL_PROTOCOL': 'SSLv2',
-##            SSL_CIPHER 	string 	The cipher specification name
-##            SSL_VERSION_INTERFACE 	string 	The mod_ssl program version
-##            SSL_VERSION_LIBRARY 	string 	The OpenSSL program version
-            }
-        
-        if self.certificate:
-            # Server certificate attributes
-            cert = open(self.certificate, 'rb').read()
-            cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert)
-            ssl_environ.update({
-                'SSL_SERVER_M_VERSION': cert.get_version(),
-                'SSL_SERVER_M_SERIAL': cert.get_serial_number(),
-##                'SSL_SERVER_V_START': Validity of server's certificate (start time),
-##                'SSL_SERVER_V_END': Validity of server's certificate (end time),
-                })
-            
-            for prefix, dn in [("I", cert.get_issuer()),
-                               ("S", cert.get_subject())]:
-                # X509Name objects don't seem to have a way to get the
-                # complete DN string. Use str() and slice it instead,
-                # because str(dn) == "<X509Name object '/C=US/ST=...'>"
-                dnstr = str(dn)[18:-2]
-                
-                wsgikey = 'SSL_SERVER_%s_DN' % prefix
-                ssl_environ[wsgikey] = dnstr
-                
-                # The DN should be of the form: /k1=v1/k2=v2, but we must allow
-                # for any value to contain slashes itself (in a URL).
-                while dnstr:
-                    pos = dnstr.rfind("=")
-                    dnstr, value = dnstr[:pos], dnstr[pos + 1:]
-                    pos = dnstr.rfind("/")
-                    dnstr, key = dnstr[:pos], dnstr[pos + 1:]
-                    if key and value:
-                        wsgikey = 'SSL_SERVER_%s_DN_%s' % (prefix, key)
-                        ssl_environ[wsgikey] = value
-        
-        return ssl_environ
-    
-    def makefile(self, sock, mode='r', bufsize=-1):
-        if SSL and isinstance(sock, SSL.ConnectionType):
-            timeout = sock.gettimeout()
-            f = SSL_fileobject(sock, mode, bufsize)
-            f.ssl_timeout = timeout
-            return f
-        else:
-            return wsgiserver.CP_fileobject(sock, mode, bufsize)
-
--- a/bundled/cherrypy/docs/cherryd.1	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,263 +0,0 @@
-.\" Man page generated from reStructuredText.
-.TH cherryd 1 "2009-06-15" "3.2.0" "web"
-.SH NAME
-cherryd \- Starts the CherryPy HTTP server as a daemon
-
-.nr rst2man-indent-level 0
-.
-.de1 rstReportMargin
-\\$1 \\n[an-margin]
-level \\n[rst2man-indent-level]
-level magin: \\n[rst2man-indent\\n[rst2man-indent-level]]
--
-\\n[rst2man-indent0]
-\\n[rst2man-indent1]
-\\n[rst2man-indent2]
-..
-.de1 INDENT
-.\" .rstReportMargin pre:
-. RS \\$1
-. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
-. nr rst2man-indent-level +1
-.\" .rstReportMargin post:
-..
-.de UNINDENT
-. RE
-.\" indent \\n[an-margin]
-.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
-.nr rst2man-indent-level -1
-.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
-.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
-..
-
-.SH SYNOPSIS
-\fBcherryd\fP [\-d] [\-f | \-s] [\-e ENV_NAME] [\-p PIDFILE_PATH] [\-P DIRPATH] [\-c CONFIG_FILE] \-i MODULE_NAME
-
-
-.SH DESCRIPTION
-\fBcherryd\fP is a Python script which starts the CherryPy webserver as a daemon.
-
-
-.SH OPTIONS
-.INDENT 0.0
-
-.TP
-.BI \-c\  CONFIG_FILE ,\ \-\-config\fn= CONFIG_FILE
-Specifies a config file which is to be read and merged into the
-CherryPy site\-wide config dict.  This option may be specified
-multiple times.  For each CONFIG_FILE specified, \fBcherryd\fP will perform
-\fBcherrypy.config.update()\fP.
-
-
-.TP
-.B \-d
-Run the server as a daemon.
-
-
-.TP
-.BI \-e\  ENV_NAME ,\ \-\-environment\fn= ENV_NAME
-Specifies the name of an environment to be applied.  An environment is a
-canned set of configuration entries.  See \fI\%ENVIRONMENTS\fP below for a
-list of the built\-in environments.
-
-
-.TP
-.B \-f
-Start a fastcgi server instead of the default HTTP server.
-
-
-.TP
-.B \-s
-Start a scgi server instead of the default HTTP server.
-
-
-.TP
-.BI \-i\  MODULE_NAME ,\ \-\-import\fn= MODULE_NAME
-Specifies a module to import.  This option may be specified multiple times.
-For each MODULE_NAME specified, \fBcherryd\fP will import the module.  This
-is how you tell \fBcherryd\fP to run your application\'s startup code.
-For all practical purposes, \fB\-i\fP is not optional; you will always need to
-specify at least one module.
-
-
-.TP
-.BI \-p\  PIDFILE_PATH ,\ \-\-pidfile\fn= PIDFILE_PATH
-Store the process id in PIDFILE_PATH.
-
-
-.TP
-.BI \-P\  DIRPATH ,\ \-\-Path\  DIRPATH
-Specifies a directory to be inserted at the head of \fBsys.path\fP.  DIRPATH
-should be an absolute path.  This option may be specified multiple times.
-\fBcherryd\fP inserts all the specified DIRPATHs into \fBsys.path\fP before it
-attempts to import modules specified with \fB\-i\fP.
-
-.UNINDENT
-For a terse summary of the options, run \fBcherryd \-\-help\fP.
-
-
-.SH EXAMPLES
-A site\-wide configuration file \fBsite.conf\fP:
-
-.INDENT 0.0
-.INDENT 3.5
-
-[global]
-.br
-server.socket_host = "0.0.0.0"
-.br
-server.socket_port = 8008
-.br
-engine.autoreload_on = False
-.br
-
-.UNINDENT
-.UNINDENT
-The application startup code in \fBstartup.py\fP:
-
-.INDENT 0.0
-.INDENT 3.5
-
-import cherrypy
-.br
-import my_controller
-.br
-cherrypy.log.error_file = \'/var/tmp/myapp\-error.log\'
-.br
-cherrypy.log.access_file = \'/var/tmp/myapp\-access.log\'
-.br
-config_root = { \'tools.encode.encoding\' : \'utf\-8\', }
-.br
-app_conf = { \'/\' : config_root }
-.br
-cherrypy.tree.mount(my_controller.Root(), script_name=\'\', config=app_conf)
-.br
-
-.UNINDENT
-.UNINDENT
-A corresponding \fBcherryd\fP command line:
-
-.INDENT 0.0
-.INDENT 3.5
-
-cherryd \-d \-c site.conf \-i startup \-p /var/log/cherrypy/my_app.pid
-.br
-
-.UNINDENT
-.UNINDENT
-
-.SH DROPPING PRIVILEGES
-If you want to serve your web application on TCP port 80 (or any port lower than
-1024), the CherryPy HTTP server needs to start as root in order to bind to the
-port.  Running a web application as root is reckless, so the application should
-drop privileges from root to some other user and group.  The application must do
-this itself, as \fBcherryd\fP does not do it for you.
-
-To drop privileges, put the following lines into your startup code,
-substituting appropriate values for \fBumask\fP, \fBuid\fP and \fBgid\fP:
-
-.INDENT 0.0
-.INDENT 3.5
-
-from cherrypy.process.plugins import DropPrivileges
-.br
-DropPrivileges(cherrypy.engine, umask=022, uid=\'nobody\', gid=\'nogroup\').subscribe()
-.br
-
-.UNINDENT
-.UNINDENT
-Note that the values for \fBuid\fP and \fBgid\fP may be either user and group
-names, or uid and gid integers.
-
-Note that you must disable the engine Autoreload plugin, because the way
-Autoreload works is by \fBexec()\fPing a new instance of the running process,
-replacing the current instance.  Since root privileges are already dropped, the
-new process instance will fail when it tries to perform a privileged operation
-such as binding to a low\-numbered TCP port.
-
-
-.SH ENVIRONMENTS
-These are the built\-in environment configurations:
-
-
-.SS staging
-.INDENT 0.0
-.INDENT 3.5
-
-\'engine.autoreload_on\': False,
-.br
-\'checker.on\': False,
-.br
-\'tools.log_headers.on\': False,
-.br
-\'request.show_tracebacks\': False,
-.br
-\'request.show_mismatched_params\': False,
-.br
-
-.UNINDENT
-.UNINDENT
-
-.SS production
-.INDENT 0.0
-.INDENT 3.5
-
-\'engine.autoreload_on\': False,
-.br
-\'checker.on\': False,
-.br
-\'tools.log_headers.on\': False,
-.br
-\'request.show_tracebacks\': False,
-.br
-\'request.show_mismatched_params\': False,
-.br
-\'log.screen\': False,
-.br
-
-.UNINDENT
-.UNINDENT
-
-.SS embedded
-.INDENT 0.0
-.INDENT 3.5
-
-# For use with CherryPy embedded in another deployment stack, e.g. Apache mod_wsgi.
-.br
-\'engine.autoreload_on\': False,
-.br
-\'checker.on\': False,
-.br
-\'tools.log_headers.on\': False,
-.br
-\'request.show_tracebacks\': False,
-.br
-\'request.show_mismatched_params\': False,
-.br
-\'log.screen\': False,
-.br
-\'engine.SIGHUP\': None,
-.br
-\'engine.SIGTERM\': None,
-.br
-
-.UNINDENT
-.UNINDENT
-
-.SH BUGS
-\fBcherryd\fP should probably accept command\-line options \fB\-\-uid\fP, \fB\-\-gid\fP, and
-\fB\-\-umask\fP, and handle dropping privileges itself.
-
-
-.SH AUTHOR
-fumanchu
-
-.nf
-cherrypy.org
-.fi
-
-.SH COPYRIGHT
-This man page is placed in the public domain
-
-.\" Generated by docutils manpage writer on 2009-06-15 15:07.
-.\" 
--- a/bundled/cherrypy/ez_setup.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,133 +0,0 @@
-#!python
-"""Bootstrap setuptools installation
-
-If you want to use setuptools in your package's setup.py, just include this
-file in the same directory with it, and add this to the top of your setup.py::
-
-    from ez_setup import use_setuptools
-    use_setuptools()
-
-If you want to require a specific version of setuptools, set a download
-mirror, or use an alternate download directory, you can do so by supplying
-the appropriate options to ``use_setuptools()``.
-
-This file can also be run as a script to install or upgrade setuptools.
-"""
-
-DEFAULT_VERSION = "0.5a13"
-DEFAULT_URL     = "http://www.python.org/packages/source/s/setuptools/"
-
-import sys, os
-
-def use_setuptools(
-    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir
-):
-    """Automatically find/download setuptools and make it available on sys.path
-
-    `version` should be a valid setuptools version number that is available
-    as an egg for download under the `download_base` URL (which should end with
-    a '/').  `to_dir` is the directory where setuptools will be downloaded, if
-    it is not already available.
-
-    If an older version of setuptools is installed, this will print a message
-    to ``sys.stderr`` and raise SystemExit in an attempt to abort the calling
-    script.
-    """
-    try:
-        import setuptools
-        if setuptools.__version__ == '0.0.1':
-            print >>sys.stderr, (
-            "You have an obsolete version of setuptools installed.  Please\n"
-            "remove it from your system entirely before rerunning this script."
-            )
-            sys.exit(2)
-
-    except ImportError:
-        egg = download_setuptools(version, download_base, to_dir)
-        sys.path.insert(0, egg)
-        import setuptools; setuptools.bootstrap_install_from = egg
-
-    import pkg_resources
-    try:
-        pkg_resources.require("setuptools>="+version)
-
-    except pkg_resources.VersionConflict:
-        # XXX could we install in a subprocess here?
-        print >>sys.stderr, (
-            "The required version of setuptools (>=%s) is not available, and\n"
-            "can't be installed while this script is running. Please install\n"
-            " a more recent version first."
-        ) % version
-        sys.exit(2)
-
-def download_setuptools(
-    version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir
-):
-    """Download setuptools from a specified location and return its filename
-
-    `version` should be a valid setuptools version number that is available
-    as an egg for download under the `download_base` URL (which should end
-    with a '/'). `to_dir` is the directory where the egg will be downloaded.
-    """
-    import urllib2, shutil
-    egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3])
-    url = download_base + egg_name + '.zip'  # XXX
-    saveto = os.path.join(to_dir, egg_name)
-    src = dst = None
-
-    if not os.path.exists(saveto):  # Avoid repeated downloads
-        try:
-            from distutils import log
-            log.warn("Downloading %s", url)
-            src = urllib2.urlopen(url)
-            # Read/write all in one block, so we don't create a corrupt file
-            # if the download is interrupted.
-            data = src.read()
-            dst = open(saveto,"wb")
-            dst.write(data)
-        finally:
-            if src: src.close()
-            if dst: dst.close()
-
-    return os.path.realpath(saveto)
-
-def main(argv, version=DEFAULT_VERSION):
-    """Install or upgrade setuptools and EasyInstall"""
-
-    try:
-        import setuptools
-    except ImportError:
-        import tempfile, shutil
-        tmpdir = tempfile.mkdtemp(prefix="easy_install-")
-        try:
-            egg = download_setuptools(version, to_dir=tmpdir)
-            sys.path.insert(0,egg)
-            from setuptools.command.easy_install import main
-            main(list(argv)+[egg])
-        finally:
-            shutil.rmtree(tmpdir)
-    else:
-        if setuptools.__version__ == '0.0.1':
-            # tell the user to uninstall obsolete version
-            use_setuptools(version)
-
-    req = "setuptools>="+version
-    import pkg_resources
-    try:
-        pkg_resources.require(req)
-    except pkg_resources.VersionConflict:
-        try:
-            from setuptools.command.easy_install import main
-        except ImportError:
-            from easy_install import main
-        main(list(argv)+[download_setuptools()])
-        sys.exit(0) # try to force an exit
-    else:
-        if argv:
-            from setuptools.command.easy_install import main
-            main(argv)
-        else:
-            print "Setuptools version",version,"or greater has been installed."
-            print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)'
-if __name__=='__main__':
-    main(sys.argv[1:])
--- a/bundled/cherrypy/make-sdist	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-rm MANIFEST
-python setup.py sdist --formats=gztar
--- a/bundled/cherrypy/setup.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,126 +0,0 @@
-"""Installs CherryPy using distutils
-
-Run:
-    python setup.py install
-
-to install this package.
-"""
-
-try:
-    from setuptools import setup
-except ImportError:
-    from distutils.core import setup
-
-from distutils.command.install import INSTALL_SCHEMES
-import sys
-import os
-import shutil
-
-required_python_version = '2.3'
-
-###############################################################################
-# arguments for the setup command
-###############################################################################
-name = "CherryPy"
-version = "3.2.0rc1"
-desc = "Object-Oriented HTTP framework"
-long_desc = "CherryPy is a pythonic, object-oriented HTTP framework"
-classifiers=[
-    #"Development Status :: 5 - Production/Stable",
-    "Development Status :: 4 - Beta",
-    "Environment :: Web Environment",
-    "Intended Audience :: Developers",
-    "License :: Freely Distributable",
-    "Operating System :: OS Independent",
-    "Programming Language :: Python",
-    "Topic :: Internet :: WWW/HTTP :: Dynamic Content",
-    "Topic :: Software Development :: Libraries :: Application Frameworks",
-]
-author="CherryPy Team"
-author_email="team@cherrypy.org"
-url="http://www.cherrypy.org"
-cp_license="BSD"
-packages=[
-    "cherrypy", "cherrypy.lib",
-    "cherrypy.tutorial", "cherrypy.test",
-    "cherrypy.wsgiserver", "cherrypy.process",
-    "cherrypy.scaffold",
-]
-download_url="http://download.cherrypy.org/cherrypy/3.2.0/"
-data_files=[
-    ('cherrypy', ['cherrypy/cherryd',
-                  'cherrypy/favicon.ico',
-                  'cherrypy/LICENSE.txt',
-                  ]),
-    ('cherrypy/process', []),
-    ('cherrypy/scaffold', ['cherrypy/scaffold/example.conf',
-                           'cherrypy/scaffold/site.conf',
-                           ]),
-    ('cherrypy/scaffold/static', ['cherrypy/scaffold/static/made_with_cherrypy_small.png',
-                                  ]),
-    ('cherrypy/test', ['cherrypy/test/style.css',
-                       'cherrypy/test/test.pem',
-                       ]),
-    ('cherrypy/test/static', ['cherrypy/test/static/index.html',
-                              'cherrypy/test/static/dirback.jpg',]),
-    ('cherrypy/tutorial',
-        [
-            'cherrypy/tutorial/tutorial.conf',
-            'cherrypy/tutorial/README.txt',
-            'cherrypy/tutorial/pdf_file.pdf',
-            'cherrypy/tutorial/custom_error.html',
-        ]
-    ),
-]
-###############################################################################
-# end arguments for setup
-###############################################################################
-
-def fix_data_files(data_files):
-    """
-    bdist_wininst seems to have a bug about where it installs data files.
-    I found a fix the django team used to work around the problem at
-    http://code.djangoproject.com/changeset/8313 .  This function
-    re-implements that solution.
-    Also see http://mail.python.org/pipermail/distutils-sig/2004-August/004134.html
-    for more info.
-    """
-    def fix_dest_path(path):
-        return '\\PURELIB\\%(path)s' % vars()
-    
-    if not 'bdist_wininst' in sys.argv: return
-    
-    data_files[:] = [
-        (fix_dest_path(path), files)
-        for path, files in data_files]
-fix_data_files(data_files)
-
-def main():
-    if sys.version < required_python_version:
-        s = "I'm sorry, but %s %s requires Python %s or later."
-        print s % (name, version, required_python_version)
-        sys.exit(1)
-    # set default location for "data_files" to
-    # platform specific "site-packages" location
-    for scheme in INSTALL_SCHEMES.values():
-        scheme['data'] = scheme['purelib']
-    
-    dist = setup(
-        name=name,
-        version=version,
-        description=desc,
-        long_description=long_desc,
-        classifiers=classifiers,
-        author=author,
-        author_email=author_email,
-        url=url,
-        license=cp_license,
-        packages=packages,
-        download_url=download_url,
-        data_files=data_files,
-        scripts=[os.path.join("cherrypy", "cherryd")],
-    )
-
-
-if __name__ == "__main__":
-    main()
Binary file bundled/cherrypy/visuals/cherrypy_logo_big.png has changed
Binary file bundled/cherrypy/visuals/cherrypy_logo_small.jpg has changed
Binary file bundled/cherrypy/visuals/favicon.ico has changed
Binary file bundled/cherrypy/visuals/made_with_cherrypy_big.png has changed
Binary file bundled/cherrypy/visuals/made_with_cherrypy_small.png has changed
--- a/bundled/webpy/.gitignore	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-*.pyc
-.DS_Store
\ No newline at end of file
--- a/bundled/webpy/ChangeLog.txt	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,293 +0,0 @@
-# web.py changelog
-
-## 2009-06-04 0.32
-
-* optional from_address to web.emailerrors
-* upgrade wsgiserver to CherryPy/3.1.2
-* support for extensions in Jinja2 templates (tx Zhang Huangbin)
-* support web.datestr for datetime.date objects also 
-* support for lists in db queries
-* new: uniq and iterview
-* fix: set debug=False when application is run with mod_wsgi (tx Patrick Swieskowski) [Bug#370904](https://bugs.launchpad.net/webpy/+bug/370904)
-* fix: make web.commify work  with decimals [Bug#317204](https://bugs.launchpad.net/webpy/+bug/317204)
-* fix: unicode issues with sqlite database [Bug#373219](https://bugs.launchpad.net/webpy/+bug/373219)
-* fix: urlquote url when the server is lighttpd [Bug#339858](https://bugs.launchpad.net/webpy/+bug/339858)
-* fix: issue with using date.format in templates
-* fix: use TOP instead of LIMIT in mssql database [Bug#324049](https://bugs.launchpad.net/webpy/+bug/324049)
-* fix: make sessions work well with expirations
-* fix: accept both list and tuple as arg values in form.Dropdown [Bug#314970](https://bugs.launchpad.net/webpy/+bug/314970)
-* fix: match parenthesis when parsing `for` statement in templates
-* fix: fix python 2.3 compatibility 
-* fix: ignore dot folders when compiling templates (tx Stuart Langridge) 
-* fix: don't consume KeyboardInterrupt and SystemExit errors 
-* fix: make application work well with iterators 
-
-## 2008-12-10: 0.31
-
-* new: browser module
-* new: test utilities
-* new: ShelfStore
-* fix: web.cookies error when default is None
-* fix: paramstyle for OracleDB (tx kromakey)
-* fix: performance issue in SQLQuery.join
-* fix: use wsgi.url_scheme to find ctx.protocol
-
-## 2008-12-06: 0.3
-
-* new: replace print with return (<i>backward-incompatible</i>)
-* new: application framework (<i>backward-incompatible</i>)
-* new: modular database system (<i>backward-incompatible</i>)
-* new: templetor reimplementation
-* new: better unicode support
-* new: debug mode (web.config.debug)
-* new: better db pooling
-* new: sessions
-* new: support for GAE
-* new: etag support
-* new: web.openid module
-* new: web.nthstr
-* fix: various form.py fixes
-* fix: python 2.6 compatibility
-* fix: file uploads are not loaded into memory
-* fix: SQLLiteral issue (Bug#180027)
-* change: web.background is moved to experimental (<i>backward-incompatible</i>) 
-* improved API doc generation (tx Colin Rothwell)
-
-## 2008-01-19: 0.23
-
-* fix: for web.background gotcha ([133079](http://bugs.launchpad.net/webpy/+bug/133079))
-* fix: for postgres unicode bug ([177265](http://bugs.launchpad.net/webpy/+bug/177265))
-* fix: web.profile behavior in python 2.5 ([133080](http://bugs.launchpad.net/webpy/+bug/133080))
-* fix: only uppercase HTTP methods are allowed. ([176415](http://bugs.launchpad.net/webpy/+bug/176415))
-* fix: transaction error in with statement ([125118](http://bugs.launchpad.net/webpy/+bug/125118))
-* fix: fix in web.reparam ([162085](http://bugs.launchpad.net/webpy/+bug/162085))
-* fix: various unicode issues ([137042](http://bugs.launchpad.net/webpy/+bug/137042), [180510](http://bugs.launchpad.net/webpy/+bug/180510), [180549](http://bugs.launchpad.net/webpy/+bug/180549), [180653](http://bugs.launchpad.net/webpy/+bug/180653))
-* new: support for https
-* new: support for secure cookies
-* new: sendmail
-* new: htmlunquote
-
-## 2007-08-23: 0.22
-
-* compatibility with new DBUtils API ([122112](https://bugs.launchpad.net/webpy/+bug/122112))
-* fix reloading ([118683](https://bugs.launchpad.net/webpy/+bug/118683))
-* fix compatibility between `changequery` and `redirect` ([118234](https://bugs.launchpad.net/webpy/+bug/118234))
-* fix relative URI in `web.redirect` ([118236](https://bugs.launchpad.net/webpy/+bug/118236))
-* fix `ctx._write` support in built-in HTTP server ([121908](https://bugs.launchpad.net/webpy/+bug/121908))
-* fix `numify` strips things after '.'s ([118644](https://bugs.launchpad.net/webpy/+bug/118644))
-* fix various unicode isssues ([114703](https://bugs.launchpad.net/webpy/+bug/114703), [120644](https://bugs.launchpad.net/webpy/+bug/120644), [124280](https://bugs.launchpad.net/webpy/+bug/124280))
-
-## 2007-05-28: 0.21
-
-* <strong>security fix:</strong> prevent bad characters in headers
-* support for cheetah template reloading                    
-* support for form validation                               
-* new `form.File`                                           
-* new `web.url`                                             
-* fix rendering issues with hidden and button inputs        
-* fix 2.3 incompatability with `numify`                     
-* fix multiple headers with same name                       
-* fix web.redirect issues when homepath is not /            
-* new CherryPy wsgi server                                  
-* new nested transactions                                   
-* new sqlliteral                                            
-
-## 2006-05-09: 0.138
-
-* New function: `intget`
-* New function: `datestr`
-* New function: `validaddr`
-* New function: `sqlwhere`
-* New function: `background`, `backgrounder`
-* New function: `changequery`
-* New function: `flush`
-* New function: `load`, `unload`
-* New variable: `loadhooks`, `unloadhooks`
-* Better docs; generating [docs](documentation) from web.py now
-* global variable `REAL_SCRIPT_NAME` can now be used to work around lighttpd madness
-* fastcgi/scgi servers now can listen on sockets
-* `output` now encodes Unicode
-* `input` now takes optional `_method` argument
-* <strong>Potentially-incompatible change:</strong> `input` now returns `badrequest` automatically when `requireds` aren't found
-* `storify` now takes lists and dictionaries as requests (see docs)
-* `redirect` now blanks any existing output
-* Quote SQL better when `db_printing` is on
-* Fix delay in `nomethod`
-* Fix `urlquote` to encode better.
-* Fix 2.3 incompatibility with `iters` (tx ??)
-* Fix duplicate headers
-* Improve `storify` docs
-* Fix `IterBetter` to raise IndexError, not KeyError
-
-## 2006-03-27: 0.137
-
-* Add function `dictfindall` (tx Steve Huffman)
-* Add support to `autodelegate` for arguments
-* Add functions `httpdate` and `parsehttpdate`
-* Add function `modified`
-* Add support for FastCGI server mode
-* Clarify `dictadd` documentation (tx Steve Huffman)
-* Changed license to public domain
-* Clean up to use `ctx` and `env` instead of `context` and `environ`
-* Improved support for PUT, DELETE, etc. (tx list)
-* Fix `ctx.fullpath` (tx Jesir Vargas)
-* Fix sqlite support (tx Dubhead)
-* Fix documentation bug in `lstrips` (tx Gregory Petrosyan)
-* Fix support for IPs and ports (1/2 tx Jesir Vargas)
-* Fix `ctx.fullpath` (tx Jesir Vargas)
-* Fix sqlite support (tx Dubhead)
-* Fix documentation bug in `lstrips` (tx Gregory Petrosyan)
-* Fix `iters` bug with sets
-* Fix some breakage introduced by Vargas's patch
-* Fix `sqlors` bug
-* Fix various small style things (tx Jesir Vargas)
-* Fix bug with `input` ignoring GET input
-
-## 2006-02-22: 0.136 (svn)
-
-* Major code cleanup (tx to Jesir Vargas for the patch).
-* 2006-02-15: 0.135
-* Really fix that mysql regression (tx Sean Leach).
-* 2006-02-15: 0.134
-* The `StopIteration` exception is now caught. This can be used by functions that do things like check to see if a user is logged in. If the user isn't, they can output a message with a login box and raise StopIteration, preventing the caller from executing.
-* Fix some documentation bugs.
-* Fix mysql regression (tx mrstone).
-
-## 2006-02-12: 0.133
-
-* Docstrings! (tx numerous, esp. Jonathan Mark (for the patch) and Guido van Rossum (for the prod))
-* Add `set` to web.iters.
-* Make the `len` returned by `query` an int (tx ??).
-* <strong>Backwards-incompatible change:</strong> `base` now called `prefixurl`.
-* <strong>Backwards-incompatible change:</strong> `autoassign` now takes `self` and `locals()` as arguments.
-
-## 2006-02-07: 0.132
-
-* New variable `iters` is now a listing of possible list-like types (currently list, tuple, and, if it exists, Set).
-* New function `dictreverse` turns `{1:2}` into `{2:1}`.
-* `Storage` now a dictionary subclass.
-* `tryall` now takes an optional prefix of functions to run.
-* `sqlors` has various improvements.
-* Fix a bunch of DB API bugs.
-* Fix bug with `storify` when it received multiple inputs (tx Ben Woosley).
-* Fix bug with returning a generator (tx Zbynek Winkler).
-* Fix bug where len returned a long on query results (tx F.S).
-
-
-## 2006-01-31: 0.131 (not officially released)
-
-* New function `_interpolate` used internally for interpolating strings.
-* Redone database API. `select`, `insert`, `update`, and `delete` all made consistent. Database queries can now do more complicated expressions like `$foo.bar` and `${a+b}`. You now have to explicitly pass the dictionary to look up variables in. Pass `vars=locals()` to get the old functionality of looking up variables .
-* New functions `sqllist` and `sqlors` generate certain kinds of SQL.
-
-## 2006-01-30: 0.13
-
-* New functions `found`, `seeother`, and `tempredirect` now let you do other kinds of redirects. `redirect` now also takes an optional status parameter. (tx many)
-* New functions `expires` and `lastmodified` make it easy to send those headers.
-* New function `gone` returns a 410 Gone (tx David Terrell).
-* New function `urlquote` applies url encoding to a string.
-* New function `iterbetter` wraps an iterator and allows you to do __getitem__s on it.
-* Have `query` return an `iterbetter` instead of an iterator.
-* Have `debugerror` show tracebacks with the innermost frame first.
-* Add `__hash__` function to `threadeddict` (and thus, `ctx`).
-* Add `context.host` value for the requested host name.
-* Add option `db_printing` that prints database queries and the time they take.
-* Add support for database pooling (tx Steve Huffman).
-* Add support for passing values to functions called by `handle`. If you do `('foo', 'value')` it will add `'value'` as an argument when it calls `foo`.
-* Add support for scgi (tx David Terrell for the patch).
-* Add support for web.py functions that are iterators (tx Brendan O'Connor for the patch).
-* Use new database cursors on each call instead of reusing one.
-* `setcookie` now takes an optional `domain` argument.
-* Fix bug in autoassign.
-* Fix bug where `debugerror` would break on objects it couldn't display.
-* Fix bug where you couldn't do `#include`s inline.
-* Fix bug with `reloader` and database calls.
-* Fix bug with `reloader` and base templates.
-* Fix bug with CGI mode on certain operating systems.
-* Fix bug where `debug` would crash if called outside a request.
-* Fix bug with `context.ip` giving weird values with proxies.
-
-## 2006-01-29: 0.129
-
-* Add Python 2.2 support.
-
-## 2006-01-28: 0.128
-
-* Fix typo in `web.profile`.
-
-## 2006-01-28: 0.127
-
-* Fix bug in error message if invalid dbn is sent (tx Panos Laganakos).
-
-## 2006-01-27: 0.126
-
-* Fix typos in Content-Type headers (tx Beat Bolli for the prod).
-
-## 2006-01-22: 0.125
-
-* Support Cheetah 2.0.
-
-## 2006-01-22: 0.124
-
-* Fix spacing bug (tx Tommi Raivio for the prod).
-
-## 2006-01-16: 0.123
-
-* Fix bug with CGI usage (tx Eddie Sowden for the prod).
-
-## 2006-01-14: 0.122
-
-* Allow DELETEs from `web.query` (tx Joost Molenaar for the prod).
-
-## 2006-01-08: 0.121
-
-* Allow import of submodules like `pkg.mod.cn` (tx Sridhar Ratna).
-* Fix a bug in `update` (tx Sergey Khenkin).
-
-## 2006-01-05: 0.12
-
-* <strong>Backwards-incompatible change:</strong> `db_parameters` is now a dictionary.
-* <strong>Backwards-incompatible change:</strong> `sumdicts` is now `dictadd`.
-* Add support for PyGreSQL, MySQL (tx Hallgrimur H. Gunnarsson).
-* Use HTML for non-Cheetah error message.
-* New function `htmlquote()`.
-* New function `tryall()`.
-* `ctx.output` can now be set to a generator. (tx Brendan O'Connor)
-
-## 2006-01-04: 0.117
-
-* Add support for psycopg 1.x. (tx Gregory Price)
-
-## 2006-01-04: 0.116
-
-* Add support for Python 2.3. (tx Evan Jones)
-
-## 2006-01-04: 0.115
-
-* Fix some bugs where database queries weren't reparameterized. Oops!
-* Fix a bug where `run()` wasn't getting the right functions.
-* Remove a debug statement accidentally left in.
-* Allow `storify` to be used on dictionaries. (tx Joseph Trent)
-
-## 2006-01-04: 0.114
-
-* Make `reloader` work on Windows. (tx manatlan)
-* Fix some small typos that affected colorization. (tx Gregory Price)
-
-## 2006-01-03: 0.113
-
-* Reorganize `run()` internals so mod_python can be used. (tx Nicholas Matsakis)
-
-## 2006-01-03: 0.112
-
-* Make `reloader` work when `code.py` is called with a full path. (tx David Terrell)
-
-## 2006-01-03: 0.111
-
-* Fixed bug in `strips()`. (tx Michael Josephson)
-
-## 2006-01-03: 0.11
-
-* First public version.
-
-
--- a/bundled/webpy/LICENSE.txt	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-web.py is in the public domain; it can be used for whatever purpose with absolutely no restrictions.
-
-CherryPy WSGI server that is included in the web.py as web.wsgiserver is licensed under CherryPy License. See web/wsgiserver/LICENSE.txt for more details.
-
--- a/bundled/webpy/experimental/background.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-"""Helpers functions to run log-running tasks."""
-from web import utils
-from web import webapi as web
-
-def background(func):
-    """A function decorator to run a long-running function as a background thread."""
-    def internal(*a, **kw):
-        web.data() # cache it
-
-        tmpctx = web._context[threading.currentThread()]
-        web._context[threading.currentThread()] = utils.storage(web.ctx.copy())
-
-        def newfunc():
-            web._context[threading.currentThread()] = tmpctx
-            func(*a, **kw)
-            myctx = web._context[threading.currentThread()]
-            for k in myctx.keys():
-                if k not in ['status', 'headers', 'output']:
-                    try: del myctx[k]
-                    except KeyError: pass
-        
-        t = threading.Thread(target=newfunc)
-        background.threaddb[id(t)] = t
-        t.start()
-        web.ctx.headers = []
-        return seeother(changequery(_t=id(t)))
-    return internal
-background.threaddb = {}
-
-def backgrounder(func):
-    def internal(*a, **kw):
-        i = web.input(_method='get')
-        if '_t' in i:
-            try:
-                t = background.threaddb[int(i._t)]
-            except KeyError:
-                return web.notfound()
-            web._context[threading.currentThread()] = web._context[t]
-            return
-        else:
-            return func(*a, **kw)
-    return internal
-
--- a/bundled/webpy/experimental/migration.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-"""Migration script to run web.py 0.23 programs using 0.3.
-
-Import this module at the beginning of your program.
-"""
-import web
-import sys
-
-def setup_database():
-    if web.config.get('db_parameters'):
-        db = web.database(**web.config.db_parameters)
-        web.insert = db.insert
-        web.select = db.select
-        web.update = db.update
-        web.delete = db.delete
-        web.query = db.query
-
-        def transact():
-            t = db.transaction()
-            web.ctx.setdefault('transaction_stack', []).append(t)
-
-        def rollback():
-            stack = web.ctx.get('transaction_stack')
-            t = stack and stack.pop()
-            t and t.rollback()
-
-        def commit():
-            stack = web.ctx.get('transaction_stack')
-            t = stack and stack.pop()
-            t and t.commit()
-
-        web.transact = transact
-        web.rollback = rollback
-        web.commit = commit
-        
-web.loadhooks = web.webapi.loadhooks = {}
-web._loadhooks = web.webapi._loadhooks = {}
-web.unloadhooks = web.webapi.unloadhooks = {}
-
-def load():
-    setup_database()
-
-web.load = load
-
-def run(urls, fvars, *middleware):
-    setup_database()
-
-    def stdout_processor(handler):
-        handler()
-        return web.ctx.get('output', '')
-
-    def hook_processor(handler):
-        for h in web.loadhooks.values() + web._loadhooks.values(): h()
-        output = handler()
-        for h in web.unloadhooks.values(): h()
-        return output
-
-    app = web.application(urls, fvars)
-    app.add_processor(stdout_processor)
-    app.add_processor(hook_processor)
-    app.run(*middleware)
-
-class _outputter:
-    """Wraps `sys.stdout` so that print statements go into the response."""
-    def __init__(self, file): self.file = file
-    def write(self, string_):
-        if hasattr(web.ctx, 'output'):
-            return output(string_)
-        else:
-            self.file.write(string_)
-    def __getattr__(self, attr): return getattr(self.file, attr)
-    def __getitem__(self, item): return self.file[item]
-
-def output(string_):
-    """Appends `string_` to the response."""
-    string_ = web.utf8(string_)
-    if web.ctx.get('flush'):
-        web.ctx._write(string_)
-    else:
-        web.ctx.output += str(string_)
-
-def _capturedstdout():
-    sysstd = sys.stdout
-    while hasattr(sysstd, 'file'):
-        if isinstance(sys.stdout, _outputter): return True
-        sysstd = sysstd.file
-    if isinstance(sys.stdout, _outputter): return True
-    return False
-
-if not _capturedstdout():
-    sys.stdout = _outputter(sys.stdout)
-
-web.run = run
-
-class Stowage(web.storage):
-    def __str__(self):
-        return self._str
-
-web.template.Stowage = web.template.stowage = Stowage
-
--- a/bundled/webpy/experimental/pwt.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,96 +0,0 @@
-import web
-import simplejson, sudo
-urls = (
-    '/sudo', 'sudoku',
-    '/length', 'length',
-)
-
-
-class pwt(object):
-    _inFunc = False
-    updated = {}
-    page = """
-<script src="/static/prototype.js"></script>
-<script src="/static/behaviour.js"></script>
-<script>
-Behaviour.register({'input': function (e) { 
-    e.onmouseup = e.onkeyup = e.onchange = function () { send(e) }
-}})
-</script>
-
-<form name="main" onsubmit="return false;">%s</form>
-
-<script>
-function send(e) {
-    ajax =  new Ajax.Request(document.location, {method:'post', parameters: 
-      Form.serialize(document.forms.main)
-    });
-}
-
-function receive(d) {
-    $H(d).keys().each(function (key) {
-        v = d[key];
-        k = document.forms.main[key];
-
-        if (k) k.value = v;
-        else $(key).innerHTML = v;
-    })
-}
-</script>
-"""
-
-    def GET(self):
-        web.header('Content-Type', 'text/html')
-        print self.page % self.form()
-    
-    def POST(self):
-        i = web.input()
-        if '_' in i: del i['_']
-        #for k, v in i.iteritems(): setattr(self, k, v)
-        
-        self._inFunc = True
-        self.work(**i)
-        self._inFunc = False
-        
-        web.header('Content-Type', 'text/javascript')
-        print 'receive('+simplejson.dumps(self.updated)+');'
-    
-    def __setattr__(self, k, v):
-        if self._inFunc and k != '_inFunc':
-            self.updated[k] = v
-        object.__setattr__(self, k, v)
-
-class sudoku(pwt):
-    def form(self):
-        import sudo
-        out = ''
-        n = 0
-        for i in range(9):
-            for j in range(9):
-                out += '<input type="text" size="1" name="%s" />' % (sudo.squares[n])
-                n += 1
-            out += '<br />'
-
-        return out
-    
-    def work(self, **kw):
-        values = dict((s, sudo.digits) for s in sudo.squares)
-        for k, v in kw.iteritems():
-            if v:
-                sudo.assign(values, k, v)
-
-        for k, v in values.iteritems():
-            if len(v) == 1:
-                setattr(self, k, v)
-
-        return values
-
-class length(pwt):
-    def form(self):
-        return '<p id="output">&nbsp;</p><input type="range" name="n" value="0" />'
-    
-    def work(self):
-        self.output = ('a' * web.intget(self.n, 0) or '&nbsp;')
-
-if __name__ == "__main__":
-    web.run(urls, globals(), web.reloader)
\ No newline at end of file
--- a/bundled/webpy/experimental/untwisted.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,134 +0,0 @@
-import random
-
-from twisted.internet import reactor, defer
-from twisted.web import http
-
-import simplejson
-
-import web
-
-class Request(http.Request):
-    def process(self):
-        self.content.seek(0, 0)
-        env = {
-          'REMOTE_ADDR': self.client.host,
-          'REQUEST_METHOD': self.method,
-          'PATH_INFO': self.path,
-          'CONTENT_LENGTH': web.intget(self.getHeader('content-length'), 0),
-          'wsgi.input': self.content
-        }
-        if '?' in self.uri:
-            env['QUERY_STRING'] = self.uri.split('?', 1)[1]
-
-        for k, v in self.received_headers.iteritems():
-            env['HTTP_' + k.upper()] = v
-        
-        if self.path.startswith('/static/'):
-            f = web.lstrips(self.path, '/static/')
-            assert '/' not in f
-            #@@@ big security hole
-            self.write(file('static/' + f).read())
-            return self.finish()
-
-        web.webapi._load(env)
-        web.ctx.trequest = self
-        result = self.actualfunc()
-        self.setResponseCode(int(web.ctx.status.split()[0]))
-        for (h, v) in web.ctx.headers:
-            self.setHeader(h, v)
-        self.write(web.ctx.output)
-        if not web.ctx.get('persist'):
-            self.finish()
-
-class Server(http.HTTPFactory):
-    def __init__(self, func):
-        self.func = func
-
-    def buildProtocol(self, addr):
-        """Generate a channel attached to this site.
-        """
-        channel = http.HTTPFactory.buildProtocol(self, addr)
-        class MyRequest(Request):
-            actualfunc = staticmethod(self.func)
-        channel.requestFactory = MyRequest
-        channel.site = self
-        return channel
-
-def runtwisted(func):
-    reactor.listenTCP(8086, Server(func))
-    reactor.run()
-
-def newrun(inp, fvars):
-    print "Running on http://0.0.0.0:8086/"
-    runtwisted(web.webpyfunc(inp, fvars, False))
-
-def iframe(url):
-    return """
-    <iframe height="0" width="0" style="display: none" src="%s"/></iframe>
-    """ % url #("http://%s.ajaxpush.lh.theinfo.org:8086%s" % (random.random(), url))
-
-class Feed:
-    def __init__(self):
-        self.sessions = []
-    
-    def subscribe(self):
-        request = web.ctx.trequest
-        self.sessions.append(request)
-        request.connectionLost = lambda reason: self.sessions.remove(request)
-        web.ctx.persist = True
-    
-    def publish(self, text):
-        for x in self.sessions:
-            x.write(text)
-
-class JSFeed(Feed):
-    def __init__(self, callback="callback"):
-        Feed.__init__(self)
-        self.callback = callback
-        
-    def publish(self, obj):
-        web.debug("publishing")
-        Feed.publish(self, 
-          '<script type="text/javascript">window.parent.%s(%s)</script>' % (self.callback, simplejson.dumps(obj) + 
-          " " * 2048))
-
-if __name__ == "__main__":
-    mfeed = JSFeed()
-
-    urls = (
-      '/', 'view',
-      '/js', 'js',
-      '/send', 'send'
-    )
-
-    class view:
-        def GET(self):
-            print """
-<script type="text/javascript">
-function callback(item) {
-  document.getElementById('content').innerHTML += "<p>" + item + "</p>";
-}
-</script>
-
-<h2>Today's News</h2>
-
-<div id="content"></div>
-
-<h2>Contribute</h2>
-<form method="post" action="/send">
-  <textarea name="text"></textarea>
-  <input type="submit" value="send" />
-</form>
-<iframe id="foo" height="0" width="0" style="display: none" src="/js"/></iframe>
-            """
-        
-    class js:
-        def GET(self):
-            mfeed.subscribe()
-    
-    class send:
-        def POST(self):
-            mfeed.publish('<p>%s</p>' % web.input().text + (" " * 2048))
-            web.seeother('/')
-    
-    newrun(urls, globals())
\ No newline at end of file
--- a/bundled/webpy/setup.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,19 +0,0 @@
-#!/usr/bin/env python
-
-# ...
-
-from distutils.core import setup
-
-setup(name='web.py',
-      version='0.32',
-      description='web.py: makes web apps',
-      author='Aaron Swartz',
-      author_email='me@aaronsw.com',
-      maintainer='Anand Chitipothu',
-      maintainer_email='anandology@gmail.com',
-      url=' http://webpy.org/',
-      packages=['web', 'web.wsgiserver', 'web.contrib'],
-      long_description="Think about the ideal way to write a web app. Write the code to make it happen.",
-      license="Public domain",
-      platforms=["any"],
-     )
--- a/bundled/webpy/test/README	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-# web.py unit tests
-
-## Setup
-
-All databases expect a database with name `webpy` with username `scott` and password `tiger`.
-
-## Running all tests
-
-To run all tests:
-
-    $ python test/alltests.py
-
-## Running individual tests
-
-To run all tests in a file:
-
-    $ python test/db.py
-
-To run all tests in a class:
-
-    $ python test/db.py SqliteTest
-
-To run a single test:
-
-    $ python test/db.py SqliteTest.testUnicode
-
-
--- a/bundled/webpy/test/alltests.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-import webtest
-
-def suite():
-    modules = ["doctests", "db", "application", "session"]
-    return webtest.suite(modules)
-    
-if __name__ == "__main__":
-    webtest.main()
--- a/bundled/webpy/test/application.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,297 +0,0 @@
-import webtest
-import time
-
-import web
-import urllib
-
-data = """
-import web
-
-urls = ("/", "%(classname)s")
-app = web.application(urls, globals(), autoreload=True)
-
-class %(classname)s:
-    def GET(self):
-        return "%(output)s"
-
-"""
-
-urls = (
-    "/iter", "do_iter",
-)
-app = web.application(urls, globals())
-
-class do_iter:
-    def GET(self):
-        yield 'hello, '
-        yield web.input(name='world').name
-
-    POST = GET
-
-def write(filename, data):
-    f = open(filename, 'w')
-    f.write(data)
-    f.close()
-
-class ApplicationTest(webtest.TestCase):
-    def test_reloader(self):
-        write('foo.py', data % dict(classname='a', output='a'))
-        import foo
-        app = foo.app
-        
-        self.assertEquals(app.request('/').data, 'a')
-        
-        # test class change
-        time.sleep(1)
-        write('foo.py', data % dict(classname='a', output='b'))
-        self.assertEquals(app.request('/').data, 'b')
-
-        # test urls change
-        time.sleep(1)
-        write('foo.py', data % dict(classname='c', output='c'))
-        self.assertEquals(app.request('/').data, 'c')
-        
-    def testUppercaseMethods(self):
-        urls = ("/", "hello")
-        app = web.application(urls, locals())
-        class hello:
-            def GET(self): return "hello"
-            def internal(self): return "secret"
-            
-        response = app.request('/', method='internal')
-        self.assertEquals(response.status, '405 Method Not Allowed')
-        
-    def testRedirect(self):
-        urls = (
-            "/a", "redirect /hello/",
-            "/b/(.*)", r"redirect /hello/\1",
-            "/hello/(.*)", "hello"
-        )
-        app = web.application(urls, locals())
-        class hello:
-            def GET(self, name): 
-                name = name or 'world'
-                return "hello " + name
-            
-        response = app.request('/a')
-        self.assertEquals(response.status, '301 Moved Permanently')
-        self.assertEquals(response.headers['Location'], 'http://0.0.0.0:8080/hello/')
-
-        response = app.request('/a?x=2')
-        self.assertEquals(response.status, '301 Moved Permanently')
-        self.assertEquals(response.headers['Location'], 'http://0.0.0.0:8080/hello/?x=2')
-
-        response = app.request('/b/foo?x=2')
-        self.assertEquals(response.status, '301 Moved Permanently')
-        self.assertEquals(response.headers['Location'], 'http://0.0.0.0:8080/hello/foo?x=2')
-        
-    def test_subdirs(self):
-        urls = (
-            "/(.*)", "blog"
-        )
-        class blog:
-            def GET(self, path):
-                return "blog " + path
-        app_blog = web.application(urls, locals())
-        
-        urls = (
-            "/blog", app_blog,
-            "/(.*)", "index"
-        )
-        class index:
-            def GET(self, path):
-                return "hello " + path
-        app = web.application(urls, locals())
-        
-        self.assertEquals(app.request('/blog/foo').data, 'blog foo')
-        self.assertEquals(app.request('/foo').data, 'hello foo')
-        
-        def processor(handler):
-            return web.ctx.path + ":" + handler()
-        app.add_processor(processor)
-        self.assertEquals(app.request('/blog/foo').data, '/blog/foo:blog foo')
-    
-    def test_subdomains(self):
-        def create_app(name):
-            urls = ("/", "index")
-            class index:
-                def GET(self):
-                    return name
-            return web.application(urls, locals())
-        
-        urls = (
-            "a.example.com", create_app('a'),
-            "b.example.com", create_app('b'),
-            ".*.example.com", create_app('*')
-        )
-        app = web.subdomain_application(urls, locals())
-        
-        def test(host, expected_result):
-            result = app.request('/', host=host)
-            self.assertEquals(result.data, expected_result)
-            
-        test('a.example.com', 'a')
-        test('b.example.com', 'b')
-        test('c.example.com', '*')
-        test('d.example.com', '*')
-        
-    def test_redirect(self):
-        urls = (
-            "/(.*)", "blog"
-        )
-        class blog:
-            def GET(self, path):
-                if path == 'foo':
-                    raise web.seeother('/login', absolute=True)
-                else:
-                    raise web.seeother('/bar')
-        app_blog = web.application(urls, locals())
-        
-        urls = (
-            "/blog", app_blog,
-            "/(.*)", "index"
-        )
-        class index:
-            def GET(self, path):
-                return "hello " + path
-        app = web.application(urls, locals())
-        
-        response = app.request('/blog/foo')
-        self.assertEquals(response.headers['Location'], 'http://0.0.0.0:8080/login')
-        
-        response = app.request('/blog/foo', env={'SCRIPT_NAME': '/x'})
-        self.assertEquals(response.headers['Location'], 'http://0.0.0.0:8080/x/login')
-
-        response = app.request('/blog/foo2')
-        self.assertEquals(response.headers['Location'], 'http://0.0.0.0:8080/blog/bar')
-        
-        response = app.request('/blog/foo2', env={'SCRIPT_NAME': '/x'})
-        self.assertEquals(response.headers['Location'], 'http://0.0.0.0:8080/x/blog/bar')
-
-    def test_processors(self):
-        urls = (
-            "/(.*)", "blog"
-        )
-        class blog:
-            def GET(self, path):
-                return 'blog ' + path
-
-        state = web.storage(x=0, y=0)
-        def f():
-            state.x += 1
-
-        app_blog = web.application(urls, locals())
-        app_blog.add_processor(web.loadhook(f))
-        
-        urls = (
-            "/blog", app_blog,
-            "/(.*)", "index"
-        )
-        class index:
-            def GET(self, path):
-                return "hello " + path
-        app = web.application(urls, locals())
-        def g():
-            state.y += 1
-        app.add_processor(web.loadhook(g))
-
-        app.request('/blog/foo')
-        assert state.x == 1 and state.y == 1, repr(state)
-        app.request('/foo')
-        assert state.x == 1 and state.y == 2, repr(state)
-        
-    def testUnicodeInput(self):
-        urls = (
-            "(/.*)", "foo"
-        )
-        class foo:
-            def GET(self, path):
-                i = web.input(name='')
-                return repr(i.name)
-                
-            def POST(self, path):
-                if path == '/multipart':
-                    i = web.input(file={})
-                    return i.file.value
-                else:
-                    i = web.input()
-                    return repr(dict(i))
-                
-        app = web.application(urls, locals())
-        
-        def f(name):
-            path = '/?' + urllib.urlencode({"name": name.encode('utf-8')})
-            self.assertEquals(app.request(path).data, repr(name))
-            
-        f(u'\u1234')
-        f(u'foo')
-
-        response = app.request('/', method='POST', data=dict(name='foo'))
-        self.assertEquals(response.data, "{'name': u'foo'}")
-        
-        data = '--boundary\r\nContent-Disposition: form-data; name="x"\r\nfoo\r\n--boundary\r\nContent-Disposition: form-data; name="file"; filename="a.txt"\r\nContent-Type: text/plain\r\n\r\na\r\n--boundary--\r\n'
-        headers = {'Content-Type': 'multipart/form-data; boundary=boundary'}
-        response = app.request('/multipart', method="POST", data=data, headers=headers)
-        self.assertEquals(response.data, 'a')
-        
-    def testCustomNotFound(self):
-        urls_a = ("/", "a")
-        urls_b = ("/", "b")
-        
-        app_a = web.application(urls_a, locals())
-        app_b = web.application(urls_b, locals())
-        
-        app_a.notfound = lambda: web.HTTPError("404 Not Found", {}, "not found 1")
-        
-        urls = (
-            "/a", app_a,
-            "/b", app_b
-        )
-        app = web.application(urls, locals())
-        
-        def assert_notfound(path, message):
-            response = app.request(path)
-            self.assertEquals(response.status.split()[0], "404")
-            self.assertEquals(response.data, message)
-            
-        assert_notfound("/a/foo", "not found 1")
-        assert_notfound("/b/foo", "not found")
-        
-        app.notfound = lambda: web.HTTPError("404 Not Found", {}, "not found 2")
-        assert_notfound("/a/foo", "not found 1")
-        assert_notfound("/b/foo", "not found 2")
-
-    def testIter(self):
-        self.assertEquals(app.request('/iter').data, 'hello, world')
-        self.assertEquals(app.request('/iter?name=web').data, 'hello, web')
-
-        self.assertEquals(app.request('/iter', method='POST').data, 'hello, world')
-        self.assertEquals(app.request('/iter', method='POST', data='name=web').data, 'hello, web')
-
-    def testUnload(self):
-        x = web.storage(a=0)
-
-        urls = (
-            "/foo", "foo",
-            "/bar", "bar"
-        )
-        class foo:
-            def GET(self):
-                return "foo"
-        class bar:
-            def GET(self):
-                raise web.notfound()
-
-        app = web.application(urls, locals())
-        def unload():
-            x.a += 1
-        app.add_processor(web.unloadhook(unload))
-
-        app.request('/foo')
-        self.assertEquals(x.a, 1)
-
-        app.request('/bar')
-        self.assertEquals(x.a, 2)
-
-if __name__ == '__main__':
-    webtest.main()
--- a/bundled/webpy/test/browser.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-import webtest
-import web
-
-urls = (
-    "/", "index",
-    "/hello/(.*)", "hello",
-    "/cookie", "cookie",
-    "/setcookie", "setcookie",
-    "/redirect", "redirect",
-)
-app = web.application(urls, globals())
-
-class index:
-    def GET(self):
-        return "welcome"
-
-class hello:
-    def GET(self, name):
-        name = name or 'world'
-        return "hello, " + name + '!'
-
-class cookie:
-    def GET(self):
-        return ",".join(sorted(web.cookies().keys()))
-
-class setcookie:
-    def GET(self):
-        i = web.input()
-        for k, v in i.items():
-            web.setcookie(k, v)
-        return "done"
-
-class redirect:
-    def GET(self):
-        i = web.input(url='/')
-        raise web.seeother(i.url)
-
-class BrowserTest(webtest.TestCase):
-    def testCookies(self):
-        b = app.browser()
-        b.open('http://0.0.0.0/setcookie?x=1&y=2')
-        b.open('http://0.0.0.0/cookie')
-        self.assertEquals(b.data, 'x,y')
-
-    def testNotfound(self):
-        b = app.browser()
-        b.open('http://0.0.0.0/notfound')
-        self.assertEquals(b.status, 404)
-
-    def testRedirect(self):
-        b = app.browser()
-
-        b.open('http://0.0.0.0:8080/redirect')
-        self.assertEquals(b.url, 'http://0.0.0.0:8080/')
-        b.open('http://0.0.0.0:8080/redirect?url=/hello/foo')
-        self.assertEquals(b.url, 'http://0.0.0.0:8080/hello/foo')
-
-        b.open('https://0.0.0.0:8080/redirect')
-        self.assertEquals(b.url, 'https://0.0.0.0:8080/')
-        b.open('https://0.0.0.0:8080/redirect?url=/hello/foo')
-        self.assertEquals(b.url, 'https://0.0.0.0:8080/hello/foo')
-
-if __name__ == "__main__":
-    webtest.main()
--- a/bundled/webpy/test/db.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,162 +0,0 @@
-"""DB test"""
-import webtest
-import web
-
-class DBTest(webtest.TestCase):
-    dbname = 'postgres'
-    driver = None
-    
-    def setUp(self):
-        self.db = webtest.setup_database(self.dbname, driver=self.driver)
-        self.db.query("CREATE TABLE person (name text, email text, active boolean)")
-
-    def tearDown(self):
-        # there might be some error with the current connection, delete from a new connection
-        self.db = webtest.setup_database(self.dbname, driver=self.driver)
-        self.db.query('DROP TABLE person')
-        
-    def _testable(self):
-        try:
-            webtest.setup_database(self.dbname, driver=self.driver)
-            return True
-        except ImportError, e:
-            print >> web.debug, str(e), "(ignoring %s)" % self.__class__.__name__
-            return False
-    
-    def testUnicode(self):
-        # Bug#177265: unicode queries throw errors
-        self.db.select('person', where='name=$name', vars={'name': u'\xf4'})
-    
-    def assertRows(self, n):
-        result = self.db.select('person')
-        self.assertEquals(len(list(result)), n)
-        
-    def testCommit(self):
-        t = self.db.transaction()
-        self.db.insert('person', False, name='user1')
-        t.commit()
-
-        t = self.db.transaction()
-        self.db.insert('person', False, name='user2')
-        self.db.insert('person', False, name='user3')
-        t.commit()
-    
-        self.assertRows(3)
-        
-    def testRollback(self):
-        t = self.db.transaction()
-        self.db.insert('person', False, name='user1')
-        self.db.insert('person', False, name='user2')
-        self.db.insert('person', False, name='user3')
-        t.rollback()        
-        self.assertRows(0)
-        
-    def testWrongQuery(self):
-        # It should be possible to run a correct query after getting an error from a wrong query.
-        try:
-            self.db.select('notthere')
-        except:
-            pass
-        self.db.select('person')
-        
-    def testNestedTransactions(self):
-        t1 = self.db.transaction()
-        self.db.insert('person', False, name='user1')
-        self.assertRows(1)        
-        
-        t2 = self.db.transaction()
-        self.db.insert('person', False, name='user2')
-        self.assertRows(2)  
-        t2.rollback()
-        self.assertRows(1)  
-        t3 = self.db.transaction()
-        self.db.insert('person', False, name='user3')
-        self.assertRows(2)  
-        t3.commit()
-        t1.commit()
-        self.assertRows(2)
-        
-    def testPooling(self):
-        # can't test pooling if DBUtils is not installed
-        try:
-            import DBUtils
-        except ImportError:
-            return
-        db = webtest.setup_database(self.dbname, pooling=True)
-        self.assertEquals(db.ctx.db.__class__.__module__, 'DBUtils.PooledDB')
-        db.select('person', limit=1)
-
-    def test_multiple_insert(self):
-        db = webtest.setup_database(self.dbname)
-        db.multiple_insert('person', [dict(name='a'), dict(name='b')], seqname=False)
-
-        assert db.select("person", where="name='a'")
-        assert db.select("person", where="name='b'")
-
-    def test_result_is_unicode(self):
-        db = webtest.setup_database(self.dbname)
-        self.db.insert('person', False, name='user')
-        name = db.select('person')[0].name
-        self.assertEquals(type(name), unicode)
-
-    def testBoolean(self):
-        def t(active):
-            name ='name-%s' % active
-            self.db.insert('person', False, name=name, active=active)
-            a = self.db.select('person', where='name=$name', vars=locals())[0].active
-            self.assertEquals(a, active)
-        t(False)
-        t(True)
-
-class PostgresTest(DBTest):
-    dbname = "postgres"
-    driver = "psycopg2"
-
-class PostgresTest_psycopg(PostgresTest):
-    driver = "psycopg"
-
-class PostgresTest_pgdb(PostgresTest):
-    driver = "pgdb"
-
-class SqliteTest(DBTest):
-    dbname = "sqlite"
-    driver = "sqlite3"
-    
-    def testNestedTransactions(self):
-        #nested transactions does not work with sqlite
-        pass
-
-class SqliteTest_pysqlite2(SqliteTest):
-    driver = "pysqlite2.dbapi2"
-
-class MySQLTest(DBTest):
-    dbname = "mysql"
-    
-    def setUp(self):
-        self.db = webtest.setup_database(self.dbname)
-        # In mysql, transactions are supported only with INNODB engine.
-        self.db.query("CREATE TABLE person (name text, email text) ENGINE=INNODB")
-
-    def testBoolean(self):
-        # boolean datatype is not suppoted in MySQL (at least until v5.0)
-        pass
-
-del DBTest
-
-def is_test(cls):
-    import inspect
-    return inspect.isclass(cls) and webtest.TestCase in inspect.getmro(cls)
-
-# ignore db tests when the required db adapter is not found.
-for t in globals().values():
-    if is_test(t) and not t('_testable')._testable():
-        del globals()[t.__name__]
-del t
-
-try:
-    import DBUtils
-except ImportError, e:
-    print >> web.debug, str(e) + "(ignoring testPooling)"
-
-if __name__ == '__main__':
-    webtest.main()
--- a/bundled/webpy/test/doctests.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-"""Run all doctests in web.py.
-"""
-import webtest
-
-def suite():
-    modules = [
-        "web.application",
-        "web.db", 
-        "web.http", 
-        "web.net", 
-        "web.session",
-        "web.template",
-        "web.utils", 
-#        "web.webapi", 
-#        "web.wsgi", 
-    ]
-    return webtest.doctest_suite(modules)
-    
-if __name__ == "__main__":
-    webtest.main()
--- a/bundled/webpy/test/session.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-import webtest
-import web
-import tempfile
-
-class SessionTest(webtest.TestCase):
-    def setUp(self):
-        app = web.auto_application()
-        session = self.make_session(app)
-        class count(app.page):
-            def GET(self):
-                session.count += 1
-                return str(session.count)
-        
-        class reset(app.page):
-            def GET(self):
-                session.kill()
-                return ""
-                
-        self.app = app
-        self.session = session
-        
-    def make_session(self, app):
-        dir = tempfile.mkdtemp()
-        store = web.session.DiskStore(tempfile.mkdtemp())
-        return web.session.Session(app, store, {'count': 0})
-        
-    def testSession(self):
-        b = self.app.browser() 
-        self.assertEquals(b.open('/count').read(), '1')
-        self.assertEquals(b.open('/count').read(), '2')
-        self.assertEquals(b.open('/count').read(), '3')
-        b.open('/reset')
-        self.assertEquals(b.open('/count').read(), '1')
-
-    def testParallelSessions(self):
-        b1 = self.app.browser()
-        b2 = self.app.browser()
-        
-        b1.open('/count')
-        
-        for i in range(1, 10):
-            self.assertEquals(b1.open('/count').read(), str(i+1))
-            self.assertEquals(b2.open('/count').read(), str(i))
-
-    def testBadSessionId(self):
-        b = self.app.browser()
-        self.assertEquals(b.open('/count').read(), '1')
-        self.assertEquals(b.open('/count').read(), '2')
-        
-        cookie = b.cookiejar._cookies['0.0.0.0']['/']['webpy_session_id']
-        cookie.value = '/etc/password'
-        self.assertEquals(b.open('/count').read(), '1')
-
-class DBSessionTest(SessionTest):
-    """Session test with db store."""
-    def make_session(self, app):
-        db = webtest.setup_database("postgres")
-        #db.printing = True
-        db.query("" 
-            + "CREATE TABLE session ("
-            + "    session_id char(128) unique not null,"
-            + "    atime timestamp default (current_timestamp at time zone 'utc'),"
-            + "    data text)"
-        )
-        store = web.session.DBStore(db, 'session')
-        return web.session.Session(app, store, {'count': 0})
-         
-    def tearDown(self):
-        # there might be some error with the current connection, delete from a new connection
-        self.db = webtest.setup_database("postgres")
-        self.db.query('DROP TABLE session')
-
-if __name__ == "__main__":
-    webtest.main()
--- a/bundled/webpy/test/webtest.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-"""webtest: test utilities.
-"""
-import sys, os
-
-# adding current directory to path to make sure local modules can be imported
-sys.path.insert(0, '.')
-
-from web.test import *
-    
-def setup_database(dbname, driver=None, pooling=False):
-    if dbname == 'sqlite':
-        db = web.database(dbn=dbname, db='webpy.db', pooling=pooling, driver=driver)
-    elif dbname == 'postgres':
-        user = os.getenv('USER')
-        db = web.database(dbn=dbname, db='webpy', user=user, pw='', pooling=pooling, driver=driver)
-    else:
-        db = web.database(dbn=dbname, db='webpy', user='scott', pw='tiger', pooling=pooling, driver=driver)
-
-    db.printing = '-v' in sys.argv
-    return db
--- a/bundled/webpy/tools/_makedoc.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-import os
-import web
-
-class Parser:
-    def __init__(self):
-        self.mode = 'normal'
-        self.text = ''
-        
-    def go(self, pyfile):
-        for line in file(pyfile):
-            if self.mode == 'in def':
-                self.text += ' ' + line.strip()
-                if line.strip().endswith(':'):
-                    if self.definition(self.text):
-                        self.text = ''
-                        self.mode = 'in func'
-                    else:
-                        self.text = ''
-                        self.mode = 'normal'
-
-            elif self.mode == 'in func':
-                if '"""' in line:
-                    self.text += line.strip().strip('"')
-                    self.mode = 'in doc'
-                    if line.count('"""') == 2:
-                        self.mode = 'normal'
-                        self.docstring(self.text)
-                        self.text = ''
-                else:
-                    self.mode = 'normal'
-
-            elif self.mode == 'in doc':
-                self.text += ' ' + line
-                if '"""' in line:
-                    self.mode = 'normal'
-                    self.docstring(self.text.strip().strip('"'))
-                    self.text = ''
-            
-            elif line.startswith('## '):
-                self.header(line.strip().strip('#'))
-            
-            elif line.startswith('def ') or line.startswith('class '):
-                self.text += line.strip().strip(':')
-                if line.strip().endswith(':'):
-                    if self.definition(self.text):
-                        self.text = ''
-                        self.mode = 'in func'
-                    else:
-                        self.text = ''
-                        self.mode = 'normal'
-                else:
-                    self.mode = 'in def'
-    
-    def clean(self, text):
-        text = text.strip()
-        text = text.replace('*', r'\*')
-        return text
-    
-    def definition(self, text):
-        text = web.lstrips(text, 'def ')
-        if text.startswith('_') or text.startswith('class _'):
-            return False
-        print '`'+text.strip()+'`'
-        return True
-    
-    def docstring(self, text):
-        print '   :', text.strip()
-        print
-    
-    def header(self, text):
-        print '##', text.strip()
-        print
-        
-for pyfile in os.listdir('trunk/web'):
-    if pyfile[-2:] == 'py':
-        print
-        print '## ' + pyfile
-        print
-        Parser().go('trunk/web/' + pyfile)
-print '`ctx`\n   :',
-print '\n'.join('    '+x for x in web.ctx.__doc__.strip().split('\n'))
--- a/bundled/webpy/tools/makedoc.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,170 +0,0 @@
-"""
-Outputs web.py docs as html
-version 2.0: documents all code, and indents nicely.
-By Colin Rothwell (TheBoff)
-"""
-import sys
-import inspect
-import markdown
-sys.path.insert(0, '..')
-
-modules = [
-    'web.application',
-    'web.contrib.template',
-    'web.db',
-    'web.debugerror',
-    'web.form',
-    'web.http',
-    'web.httpserver',
-    'web.net',
-    'web.session',
-    'web.template',
-    'web.utils',
-    'web.webapi',
-    'web.webopenid',
-    'web.wsgi'
-]
-
-item_start = '<code class="%s">'
-item_end = '</code>'
-
-indent_amount = 30
-
-doc_these = ( #These are the types of object that should be docced
-    'module',
-    'classobj',
-    'instancemethod',
-    'function',
-    'type',
-    'property',    
-)
-
-not_these_names = ( #Any particular object names that shouldn't be doced
-    'fget',
-    'fset',
-    'fdel',
-    'storage', #These stop the lower case versions getting docced
-    'memoize',
-    'iterbetter',
-    'capturesstdout',
-    'profile',
-    'threadeddict',
-    'd', #Don't know what this is, but only only conclude it shouldn't be doc'd
-)
-
-css = '''
-<style type="text/css">
-.module {
-    font-size: 130%;
-    font-weight: bold;
-}
-
-.function, .class, .type {
-    font-size: 120%;
-    font-weight: bold;
-}
-
-.method, .property {
-    font-size: 115%;
-    font-weight: bold;
-}
-
-.ts {
-    font-size: small;
-    font-weight: lighter;
-    color: grey;
-}
-
-#contents_link {
-    position: fixed;
-    top: 0;
-    right: 0;
-    padding: 5px;
-    background: rgba(255, 255, 255, 0.5);
-}
-
-#contents_link a:hover {
-    font-weight: bold;
-}
-</style>
-'''
-
-
-indent_start = '<div style="margin-left:%dpx">'
-indent_end = '</div>'
-
-header = '''
-<div id="contents_link">
-<a href="#top">Back to contents</a>
-</div>
-'''
-
-def type_string(ob):
-    return str(type(ob)).split("'")[1]
-    
-def ts_css(text):
-    """applies nice css to the type string"""
-    return '<span class="ts">%s</span>' % text
-    
-def arg_string(func):
-    """Returns a nice argstring for a function or method"""
-    return inspect.formatargspec(*inspect.getargspec(func))
-
-def recurse_over(ob, name, indent_level=0):
-    ts = type_string(ob)    
-    if not ts in doc_these: return #stos what shouldn't be docced getting docced
-    if indent_level > 0 and ts == 'module': return #Stops it getting into the stdlib    
-    if name in not_these_names: return #Stops things we don't want getting docced
-    
-    indent = indent_level * indent_amount #Indents nicely
-    ds_indent = indent + (indent_amount / 2)
-    if indent_level > 0: print indent_start % indent
-    
-    argstr = ''
-    if ts.endswith(('function', 'method')):
-        argstr = arg_string(ob)
-    elif ts == 'classobj' or ts == 'type':
-        if ts == 'classobj': ts = 'class'
-        if hasattr(ob, '__init__'):
-            if type_string(ob.__init__) == 'instancemethod':
-                argstr = arg_string(ob.__init__)
-        else:
-            argstr = '(self)'
-    if ts == 'instancemethod': ts = 'method' #looks much nicer
-    
-    ds = inspect.getdoc(ob)
-    if ds is None: ds = ''
-    ds = markdown.Markdown(ds)
-    
-    mlink = '<a name="%s">' % name if ts == 'module' else '' 
-    mend = '</a>' if ts == 'module' else ''
-                
-    print ''.join(('<p>', ts_css(ts), item_start % ts, ' ', mlink, name, argstr,
-            mend, item_end, '<br />'))
-    print ''.join((indent_start % ds_indent, ds, indent_end, '</p>'))
-    #Although ''.join looks wierd, it's alot faster is string addition    
-    members = ''
-    
-    if hasattr(ob, '__all__'): members = ob.__all__
-    else: members = [item for item in dir(ob) if not item.startswith('_')] 
-    
-    if not 'im_class' in members:    
-        for name in members:
-            recurse_over(getattr(ob, name), name, indent_level + 1)
-    if indent_level > 0: print indent_end
-
-def main():
-    print '<div>' #Stops markdown vandalising my html.
-    print css
-    print header
-    print '<ul>'
-    for name in modules:
-        print '<li><a href="#%(name)s">%(name)s</a></li>' % dict(name=name)
-    print '</ul>' 
-    for name in modules:
-        mod = __import__(name, {}, {}, 'x')
-        recurse_over(mod, name)
-    print '</div>'
-        
-if __name__ == '__main__':
-    main()
\ No newline at end of file
--- a/bundled/webpy/tools/markdown.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,677 +0,0 @@
-#!/usr/bin/python
-import re, md5, sys, string
-
-"""markdown.py: A Markdown-styled-text to HTML converter in Python.
-
-Usage:
-  ./markdown.py textfile.markdown
- 
-Calling:
-  import markdown
-  somehtml = markdown.markdown(sometext)
-
-For other versions of markdown, see: 
-  http://www.freewisdom.org/projects/python-markdown/
-  http://en.wikipedia.org/wiki/Markdown
-"""
-
-__version__ = '1.0.1-2' # port of 1.0.1
-__license__ = "GNU GPL 2"
-__author__ = [
-  'John Gruber <http://daringfireball.net/>',
-  'Tollef Fog Heen <tfheen@err.no>', 
-  'Aaron Swartz <me@aaronsw.com>'
-]
-
-def htmlquote(text):
-    """Encodes `text` for raw use in HTML."""
-    text = text.replace("&", "&amp;") # Must be done first!
-    text = text.replace("<", "&lt;")
-    text = text.replace(">", "&gt;")
-    text = text.replace("'", "&#39;")
-    text = text.replace('"', "&quot;")
-    return text
-
-def semirandom(seed):
-    x = 0
-    for c in md5.new(seed).digest(): x += ord(c)
-    return x / (255*16.)
-
-class _Markdown:
-    emptyelt = " />"
-    tabwidth = 4
-
-    escapechars = '\\`*_{}[]()>#+-.!'
-    escapetable = {}
-    for char in escapechars:
-        escapetable[char] = md5.new(char).hexdigest()
-    
-    r_multiline = re.compile("\n{2,}")
-    r_stripspace = re.compile(r"^[ \t]+$", re.MULTILINE)
-    def parse(self, text):
-        self.urls = {}
-        self.titles = {}
-        self.html_blocks = {}
-        self.list_level = 0
-        
-        text = text.replace("\r\n", "\n")
-        text = text.replace("\r", "\n")
-        text += "\n\n"
-        text = self._Detab(text)
-        text = self.r_stripspace.sub("", text)
-        text = self._HashHTMLBlocks(text)
-        text = self._StripLinkDefinitions(text)
-        text = self._RunBlockGamut(text)
-        text = self._UnescapeSpecialChars(text)
-        return text
-    
-    r_StripLinkDefinitions = re.compile(r"""
-    ^[ ]{0,%d}\[(.+)\]:  # id = $1
-      [ \t]*\n?[ \t]*
-    <?(\S+?)>?           # url = $2
-      [ \t]*\n?[ \t]*
-    (?:
-      (?<=\s)            # lookbehind for whitespace
-      [\"\(]             # " is backlashed so it colorizes our code right
-      (.+?)              # title = $3
-      [\"\)]
-      [ \t]*
-    )?                   # title is optional
-    (?:\n+|\Z)
-    """ % (tabwidth-1), re.MULTILINE|re.VERBOSE)
-    def _StripLinkDefinitions(self, text):
-        def replacefunc(matchobj):
-            (t1, t2, t3) = matchobj.groups()
-            #@@ case sensitivity?
-            self.urls[t1.lower()] = self._EncodeAmpsAndAngles(t2)
-            if t3 is not None:
-                self.titles[t1.lower()] = t3.replace('"', '&quot;')
-            return ""
-
-        text = self.r_StripLinkDefinitions.sub(replacefunc, text)
-        return text
-
-    blocktagsb = r"p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|math"
-    blocktagsa = blocktagsb + "|ins|del"
-    
-    r_HashHTMLBlocks1 = re.compile(r"""
-    (            # save in $1
-    ^            # start of line  (with /m)
-    <(%s)        # start tag = $2
-    \b           # word break
-    (.*\n)*?     # any number of lines, minimally matching
-    </\2>        # the matching end tag
-    [ \t]*       # trailing spaces/tabs
-    (?=\n+|$)    # followed by a newline or end of document
-    )
-    """ % blocktagsa, re.MULTILINE | re.VERBOSE)
-
-    r_HashHTMLBlocks2 = re.compile(r"""
-    (            # save in $1
-    ^            # start of line  (with /m)
-    <(%s)        # start tag = $2
-    \b           # word break
-    (.*\n)*?     # any number of lines, minimally matching
-    .*</\2>      # the matching end tag
-    [ \t]*       # trailing spaces/tabs
-    (?=\n+|\Z)   # followed by a newline or end of document
-    )
-    """ % blocktagsb, re.MULTILINE | re.VERBOSE)
-
-    r_HashHR = re.compile(r"""
-    (?:
-    (?<=\n\n)    # Starting after a blank line
-    |            # or
-    \A\n?        # the beginning of the doc
-    )
-    (            # save in $1
-    [ ]{0,%d}
-    <(hr)        # start tag = $2
-    \b           # word break
-    ([^<>])*?    # 
-    /?>          # the matching end tag
-    [ \t]*
-    (?=\n{2,}|\Z)# followed by a blank line or end of document
-    )
-    """ % (tabwidth-1), re.VERBOSE)
-    r_HashComment = re.compile(r"""
-    (?:
-    (?<=\n\n)    # Starting after a blank line
-    |            # or
-    \A\n?        # the beginning of the doc
-    )
-    (            # save in $1
-    [ ]{0,%d}
-    (?: 
-      <!
-      (--.*?--\s*)+
-      >
-    )
-    [ \t]*
-    (?=\n{2,}|\Z)# followed by a blank line or end of document
-    )
-    """ % (tabwidth-1), re.VERBOSE)
-
-    def _HashHTMLBlocks(self, text):
-        def handler(m):
-            key = md5.new(m.group(1)).hexdigest()
-            self.html_blocks[key] = m.group(1)
-            return "\n\n%s\n\n" % key
-
-        text = self.r_HashHTMLBlocks1.sub(handler, text)
-        text = self.r_HashHTMLBlocks2.sub(handler, text)
-        oldtext = text
-        text = self.r_HashHR.sub(handler, text)
-        text = self.r_HashComment.sub(handler, text)
-        return text
-
-    #@@@ wrong!
-    r_hr1 = re.compile(r'^[ ]{0,2}([ ]?\*[ ]?){3,}[ \t]*$', re.M)
-    r_hr2 = re.compile(r'^[ ]{0,2}([ ]?-[ ]?){3,}[ \t]*$', re.M)
-    r_hr3 = re.compile(r'^[ ]{0,2}([ ]?_[ ]?){3,}[ \t]*$', re.M)
-	
-    def _RunBlockGamut(self, text):
-        text = self._DoHeaders(text)
-        for x in [self.r_hr1, self.r_hr2, self.r_hr3]:
-            text = x.sub("\n<hr%s\n" % self.emptyelt, text);
-        text = self._DoLists(text)
-        text = self._DoCodeBlocks(text)
-        text = self._DoBlockQuotes(text)
-
-    	# We did this in parse()
-    	# to escape the source
-    	# now it's stuff _we_ made
-    	# so we don't wrap it in <p>s.
-        text = self._HashHTMLBlocks(text)
-        text = self._FormParagraphs(text)
-        return text
-
-    r_NewLine = re.compile(" {2,}\n")
-    def _RunSpanGamut(self, text):
-        text = self._DoCodeSpans(text)
-        text = self._EscapeSpecialChars(text)
-        text = self._DoImages(text)
-        text = self._DoAnchors(text)
-        text = self._DoAutoLinks(text)
-        text = self._EncodeAmpsAndAngles(text)
-        text = self._DoItalicsAndBold(text)
-        text = self.r_NewLine.sub(" <br%s\n" % self.emptyelt, text)
-        return text
-
-    def _EscapeSpecialChars(self, text):
-        tokens = self._TokenizeHTML(text)
-        text = ""
-        for cur_token in tokens:
-            if cur_token[0] == "tag":
-                cur_token[1] = cur_token[1].replace('*', self.escapetable["*"])
-                cur_token[1] = cur_token[1].replace('_', self.escapetable["_"])
-                text += cur_token[1]
-            else:
-                text += self._EncodeBackslashEscapes(cur_token[1])
-        return text
-
-    r_DoAnchors1 = re.compile(
-          r""" (                 # wrap whole match in $1
-                  \[
-                    (.*?)        # link text = $2 
-                    # [for bracket nesting, see below]
-                  \]
-
-                  [ ]?           # one optional space
-                  (?:\n[ ]*)?    # one optional newline followed by spaces
-
-                  \[
-                    (.*?)        # id = $3
-                  \]
-                )
-    """, re.S|re.VERBOSE)
-    r_DoAnchors2 = re.compile(
-          r""" (                   # wrap whole match in $1
-                  \[
-                    (.*?)          # link text = $2
-                  \]
-                  \(               # literal paren
-                        [ \t]*
-                        <?(.+?)>?  # href = $3
-                        [ \t]*
-                        (          # $4
-                          ([\'\"]) # quote char = $5
-                          (.*?)    # Title = $6
-                          \5       # matching quote
-                        )?         # title is optional
-                  \)
-                )
-    """, re.S|re.VERBOSE)
-    def _DoAnchors(self, text): 
-        # We here don't do the same as the perl version, as python's regex
-        # engine gives us no way to match brackets.
-
-        def handler1(m):
-            whole_match = m.group(1)
-            link_text = m.group(2)
-            link_id = m.group(3).lower()
-            if not link_id: link_id = link_text.lower()
-            title = self.titles.get(link_id, None)
-                
-
-            if self.urls.has_key(link_id):
-                url = self.urls[link_id]
-                url = url.replace("*", self.escapetable["*"])
-                url = url.replace("_", self.escapetable["_"])
-                res = '<a href="%s"' % htmlquote(url)
-
-                if title:
-                    title = title.replace("*", self.escapetable["*"])
-                    title = title.replace("_", self.escapetable["_"])
-                    res += ' title="%s"' % htmlquote(title)
-                res += ">%s</a>" % htmlquote(link_text)
-            else:
-                res = whole_match
-            return res
-
-        def handler2(m):
-            whole_match = m.group(1)
-            link_text = m.group(2)
-            url = m.group(3)
-            title = m.group(6)
-
-            url = url.replace("*", self.escapetable["*"])
-            url = url.replace("_", self.escapetable["_"])
-            res = '''<a href="%s"''' % htmlquote(url)
-            
-            if title:
-                title = title.replace('"', '&quot;')
-                title = title.replace("*", self.escapetable["*"])
-                title = title.replace("_", self.escapetable["_"])
-                res += ' title="%s"' % htmlquote(title)
-            res += ">%s</a>" % htmlquote(link_text)
-            return res
-
-        text = self.r_DoAnchors1.sub(handler1, text)
-        text = self.r_DoAnchors2.sub(handler2, text)
-        return text
-
-    r_DoImages1 = re.compile(
-           r""" (                       # wrap whole match in $1
-                  !\[
-                    (.*?)               # alt text = $2
-                  \]
-
-                  [ ]?                  # one optional space
-                  (?:\n[ ]*)?           # one optional newline followed by spaces
-
-                  \[
-                    (.*?)               # id = $3
-                  \]
-
-                )
-    """, re.VERBOSE|re.S)
-
-    r_DoImages2 = re.compile(
-          r""" (                        # wrap whole match in $1
-                  !\[
-                    (.*?)               # alt text = $2
-                  \]
-                  \(                    # literal paren
-                        [ \t]*
-                        <?(\S+?)>?      # src url = $3
-                        [ \t]*
-                        (               # $4
-                        ([\'\"])        # quote char = $5
-                          (.*?)         # title = $6
-                          \5            # matching quote
-                          [ \t]*
-                        )?              # title is optional
-                  \)
-                )
-    """, re.VERBOSE|re.S)
-
-    def _DoImages(self, text):
-        def handler1(m):
-            whole_match = m.group(1)
-            alt_text = m.group(2)
-            link_id = m.group(3).lower()
-
-            if not link_id:
-                link_id = alt_text.lower()
-
-            alt_text = alt_text.replace('"', "&quot;")
-            if self.urls.has_key(link_id):
-                url = self.urls[link_id]
-                url = url.replace("*", self.escapetable["*"])
-                url = url.replace("_", self.escapetable["_"])
-                res = '''<img src="%s" alt="%s"''' % (htmlquote(url), htmlquote(alt_text))
-                if self.titles.has_key(link_id):
-                    title = self.titles[link_id]
-                    title = title.replace("*", self.escapetable["*"])
-                    title = title.replace("_", self.escapetable["_"])
-                    res += ' title="%s"' % htmlquote(title)
-                res += self.emptyelt
-            else:
-                res = whole_match
-            return res
-
-        def handler2(m):
-            whole_match = m.group(1)
-            alt_text = m.group(2)
-            url = m.group(3)
-            title = m.group(6) or ''
-            
-            alt_text = alt_text.replace('"', "&quot;")
-            title = title.replace('"', "&quot;")
-            url = url.replace("*", self.escapetable["*"])
-            url = url.replace("_", self.escapetable["_"])
-            res = '<img src="%s" alt="%s"' % (htmlquote(url), htmlquote(alt_text))
-            if title is not None:
-                title = title.replace("*", self.escapetable["*"])
-                title = title.replace("_", self.escapetable["_"])
-                res += ' title="%s"' % htmlquote(title)
-            res += self.emptyelt
-            return res
-
-        text = self.r_DoImages1.sub(handler1, text)
-        text = self.r_DoImages2.sub(handler2, text)
-        return text
-    
-    r_DoHeaders = re.compile(r"^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+", re.VERBOSE|re.M)
-    def _DoHeaders(self, text):
-        def findheader(text, c, n):
-            textl = text.split('\n')
-            for i in xrange(len(textl)):
-                if i >= len(textl): continue
-                count = textl[i].strip().count(c)
-                if count > 0 and count == len(textl[i].strip()) and textl[i+1].strip() == '' and textl[i-1].strip() != '':
-                    textl = textl[:i] + textl[i+1:]
-                    textl[i-1] = '<h'+n+'>'+self._RunSpanGamut(textl[i-1])+'</h'+n+'>'
-                    textl = textl[:i] + textl[i+1:]
-            text = '\n'.join(textl)
-            return text
-        
-        def handler(m):
-            level = len(m.group(1))
-            header = self._RunSpanGamut(m.group(2))
-            return "<h%s>%s</h%s>\n\n" % (level, header, level)
-
-        text = findheader(text, '=', '1')
-        text = findheader(text, '-', '2')
-        text = self.r_DoHeaders.sub(handler, text)
-        return text
-    
-    rt_l = r"""
-    (
-      (
-        [ ]{0,%d}
-        ([*+-]|\d+[.])
-        [ \t]+
-      )
-      (?:.+?)
-      (
-        \Z
-      |
-        \n{2,}
-        (?=\S)
-        (?![ \t]* ([*+-]|\d+[.])[ \t]+)
-      )
-    )
-    """ % (tabwidth - 1)
-    r_DoLists = re.compile('^'+rt_l, re.M | re.VERBOSE | re.S)
-    r_DoListsTop = re.compile(
-      r'(?:\A\n?|(?<=\n\n))'+rt_l, re.M | re.VERBOSE | re.S)
-    
-    def _DoLists(self, text):
-        def handler(m):
-            list_type = "ol"
-            if m.group(3) in [ "*", "-", "+" ]:
-                list_type = "ul"
-            listn = m.group(1)
-            listn = self.r_multiline.sub("\n\n\n", listn)
-            res = self._ProcessListItems(listn)
-            res = "<%s>\n%s</%s>\n" % (list_type, res, list_type)
-            return res
-            
-        if self.list_level:
-            text = self.r_DoLists.sub(handler, text)
-        else:
-            text = self.r_DoListsTop.sub(handler, text)
-        return text
-
-    r_multiend = re.compile(r"\n{2,}\Z")
-    r_ProcessListItems = re.compile(r"""
-    (\n)?                            # leading line = $1
-    (^[ \t]*)                        # leading whitespace = $2
-    ([*+-]|\d+[.]) [ \t]+            # list marker = $3
-    ((?:.+?)                         # list item text = $4
-    (\n{1,2}))
-    (?= \n* (\Z | \2 ([*+-]|\d+[.]) [ \t]+))
-    """, re.VERBOSE | re.M | re.S)
-
-    def _ProcessListItems(self, text):
-        self.list_level += 1
-        text = self.r_multiend.sub("\n", text)
-        
-        def handler(m):
-            item = m.group(4)
-            leading_line = m.group(1)
-            leading_space = m.group(2)
-
-            if leading_line or self.r_multiline.search(item):
-                item = self._RunBlockGamut(self._Outdent(item))
-            else:
-                item = self._DoLists(self._Outdent(item))
-                if item[-1] == "\n": item = item[:-1] # chomp
-                item = self._RunSpanGamut(item)
-            return "<li>%s</li>\n" % item
-
-        text = self.r_ProcessListItems.sub(handler, text)
-        self.list_level -= 1
-        return text
-    
-    r_DoCodeBlocks = re.compile(r"""
-    (?:\n\n|\A)
-    (                 # $1 = the code block
-    (?:
-    (?:[ ]{%d} | \t)  # Lines must start with a tab or equiv
-    .*\n+
-    )+
-    )
-    ((?=^[ ]{0,%d}\S)|\Z) # Lookahead for non-space/end of doc
-    """ % (tabwidth, tabwidth), re.M | re.VERBOSE)
-    def _DoCodeBlocks(self, text):
-        def handler(m):
-            codeblock = m.group(1)
-            codeblock = self._EncodeCode(self._Outdent(codeblock))
-            codeblock = self._Detab(codeblock)
-            codeblock = codeblock.lstrip("\n")
-            codeblock = codeblock.rstrip()
-            res = "\n\n<pre><code>%s\n</code></pre>\n\n" % codeblock
-            return res
-
-        text = self.r_DoCodeBlocks.sub(handler, text)
-        return text
-    r_DoCodeSpans = re.compile(r"""
-    (`+)            # $1 = Opening run of `
-    (.+?)           # $2 = The code block
-    (?<!`)
-    \1              # Matching closer
-    (?!`)
-    """, re.I|re.VERBOSE)
-    def _DoCodeSpans(self, text):
-        def handler(m):
-            c = m.group(2)
-            c = c.strip()
-            c = self._EncodeCode(c)
-            return "<code>%s</code>" % c
-
-        text = self.r_DoCodeSpans.sub(handler, text)
-        return text
-    
-    def _EncodeCode(self, text):
-        text = text.replace("&","&amp;")
-        text = text.replace("<","&lt;")
-        text = text.replace(">","&gt;")
-        for c in "*_{}[]\\":
-            text = text.replace(c, self.escapetable[c])
-        return text
-
-    
-    r_DoBold = re.compile(r"(\*\*|__) (?=\S) (.+?[*_]*) (?<=\S) \1", re.VERBOSE | re.S)
-    r_DoItalics = re.compile(r"(\*|_) (?=\S) (.+?) (?<=\S) \1", re.VERBOSE | re.S)
-    def _DoItalicsAndBold(self, text):
-        text = self.r_DoBold.sub(r"<strong>\2</strong>", text)
-        text = self.r_DoItalics.sub(r"<em>\2</em>", text)
-        return text
-    
-    r_start = re.compile(r"^", re.M)
-    r_DoBlockQuotes1 = re.compile(r"^[ \t]*>[ \t]?", re.M)
-    r_DoBlockQuotes2 = re.compile(r"^[ \t]+$", re.M)
-    r_DoBlockQuotes3 = re.compile(r"""
-    (                       # Wrap whole match in $1
-     (
-       ^[ \t]*>[ \t]?       # '>' at the start of a line
-       .+\n                 # rest of the first line
-       (.+\n)*              # subsequent consecutive lines
-       \n*                  # blanks
-      )+
-    )""", re.M | re.VERBOSE)
-    r_protectpre = re.compile(r'(\s*<pre>.+?</pre>)', re.S)
-    r_propre = re.compile(r'^  ', re.M)
-
-    def _DoBlockQuotes(self, text):
-        def prehandler(m):
-            return self.r_propre.sub('', m.group(1))
-                
-        def handler(m):
-            bq = m.group(1)
-            bq = self.r_DoBlockQuotes1.sub("", bq)
-            bq = self.r_DoBlockQuotes2.sub("", bq)
-            bq = self._RunBlockGamut(bq)
-            bq = self.r_start.sub("  ", bq)
-            bq = self.r_protectpre.sub(prehandler, bq)
-            return "<blockquote>\n%s\n</blockquote>\n\n" % bq
-            
-        text = self.r_DoBlockQuotes3.sub(handler, text)
-        return text
-
-    r_tabbed = re.compile(r"^([ \t]*)")
-    def _FormParagraphs(self, text):
-        text = text.strip("\n")
-        grafs = self.r_multiline.split(text)
-
-        for g in xrange(len(grafs)):
-            t = grafs[g].strip() #@@?
-            if not self.html_blocks.has_key(t):
-                t = self._RunSpanGamut(t)
-                t = self.r_tabbed.sub(r"<p>", t)
-                t += "</p>"
-                grafs[g] = t
-
-        for g in xrange(len(grafs)):
-            t = grafs[g].strip()
-            if self.html_blocks.has_key(t):
-                grafs[g] = self.html_blocks[t]
-        
-        return "\n\n".join(grafs)
-
-    r_EncodeAmps = re.compile(r"&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)")
-    r_EncodeAngles = re.compile(r"<(?![a-z/?\$!])")
-    def _EncodeAmpsAndAngles(self, text):
-        text = self.r_EncodeAmps.sub("&amp;", text)
-        text = self.r_EncodeAngles.sub("&lt;", text)
-        return text
-
-    def _EncodeBackslashEscapes(self, text):
-        for char in self.escapechars:
-            text = text.replace("\\" + char, self.escapetable[char])
-        return text
-    
-    r_link = re.compile(r"<((https?|ftp):[^\'\">\s]+)>", re.I)
-    r_email = re.compile(r"""
-      <
-      (?:mailto:)?
-      (
-         [-.\w]+
-         \@
-         [-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+
-      )
-      >""", re.VERBOSE|re.I)
-    def _DoAutoLinks(self, text):
-        text = self.r_link.sub(r'<a href="\1">\1</a>', text)
-
-        def handler(m):
-            l = m.group(1)
-            return self._EncodeEmailAddress(self._UnescapeSpecialChars(l))
-    
-        text = self.r_email.sub(handler, text)
-        return text
-    
-    r_EncodeEmailAddress = re.compile(r">.+?:")
-    def _EncodeEmailAddress(self, text):
-        encode = [
-            lambda x: "&#%s;" % ord(x),
-            lambda x: "&#x%X;" % ord(x),
-            lambda x: x
-        ]
-
-        text = "mailto:" + text
-        addr = ""
-        for c in text:
-            if c == ':': addr += c; continue
-            
-            r = semirandom(addr)
-            if r < 0.45:
-                addr += encode[1](c)
-            elif r > 0.9 and c != '@':
-                addr += encode[2](c)
-            else:
-                addr += encode[0](c)
-
-        text = '<a href="%s">%s</a>' % (addr, addr)
-        text = self.r_EncodeEmailAddress.sub('>', text)
-        return text
-
-    def _UnescapeSpecialChars(self, text):
-        for key in self.escapetable.keys():
-            text = text.replace(self.escapetable[key], key)
-        return text
-    
-    tokenize_depth = 6
-    tokenize_nested_tags = '|'.join([r'(?:<[a-z/!$](?:[^<>]'] * tokenize_depth) + (')*>)' * tokenize_depth)
-    r_TokenizeHTML = re.compile(
-      r"""(?: <! ( -- .*? -- \s* )+ > ) |  # comment
-          (?: <\? .*? \?> ) |              # processing instruction
-          %s                               # nested tags
-    """ % tokenize_nested_tags, re.I|re.VERBOSE)
-    def _TokenizeHTML(self, text):
-        pos = 0
-        tokens = []
-        matchobj = self.r_TokenizeHTML.search(text, pos)
-        while matchobj:
-            whole_tag = matchobj.string[matchobj.start():matchobj.end()]
-            sec_start = matchobj.end()
-            tag_start = sec_start - len(whole_tag)
-            if pos < tag_start:
-                tokens.append(["text", matchobj.string[pos:tag_start]])
-
-            tokens.append(["tag", whole_tag])
-            pos = sec_start
-            matchobj = self.r_TokenizeHTML.search(text, pos)
-
-        if pos < len(text):
-            tokens.append(["text", text[pos:]])
-        return tokens
-
-    r_Outdent = re.compile(r"""^(\t|[ ]{1,%d})""" % tabwidth, re.M)
-    def _Outdent(self, text):
-        text = self.r_Outdent.sub("", text)
-        return text    
-
-    def _Detab(self, text): return text.expandtabs(self.tabwidth)
-
-def Markdown(*args, **kw): return _Markdown().parse(*args, **kw)
-markdown = Markdown
-
-if __name__ == '__main__':
-    if len(sys.argv) > 1:
-        print Markdown(open(sys.argv[1]).read())
-    else:
-        print Markdown(sys.stdin.read())
--- a/bundled/webpy/web/__init__.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-#!/usr/bin/env python
-"""web.py: makes web apps (http://webpy.org)"""
-
-from __future__ import generators
-
-__version__ = "0.32"
-__author__ = [
-    "Aaron Swartz <me@aaronsw.com>",
-    "Anand Chitipothu <anandology@gmail.com>"
-]
-__license__ = "public domain"
-__contributors__ = "see http://webpy.org/changes"
-
-import utils, db, net, wsgi, http, webapi, httpserver, debugerror
-import template, form
-
-import session
-
-from utils import *
-from db import *
-from net import *
-from wsgi import *
-from http import *
-from webapi import *
-from httpserver import *
-from debugerror import *
-from application import *
-from browser import *
-import test
-try:
-    import webopenid as openid
-except ImportError:
-    pass # requires openid module
-
--- a/bundled/webpy/web/application.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,667 +0,0 @@
-#!/usr/bin/python
-"""
-Web application
-(from web.py)
-"""
-import webapi as web
-import webapi, wsgi, utils
-import debugerror
-from utils import lstrips, safeunicode
-import sys
-
-import urllib
-import traceback
-import itertools
-import os
-import re
-import types
-from exceptions import SystemExit
-
-try:
-    import wsgiref.handlers
-except ImportError:
-    pass # don't break people with old Pythons
-
-__all__ = [
-    "application", "auto_application",
-    "subdir_application", "subdomain_application", 
-    "loadhook", "unloadhook",
-    "autodelegate"
-]
-
-class application:
-    """
-    Application to delegate requests based on path.
-    
-        >>> urls = ("/hello", "hello")
-        >>> app = application(urls, globals())
-        >>> class hello:
-        ...     def GET(self): return "hello"
-        >>>
-        >>> app.request("/hello").data
-        'hello'
-    """
-    def __init__(self, mapping=(), fvars={}, autoreload=None):
-        if autoreload is None:
-            autoreload = web.config.get('debug', False)
-        self.mapping = mapping
-        self.fvars = fvars
-        self.processors = []
-        
-        self.add_processor(loadhook(self._load))
-        self.add_processor(unloadhook(self._unload))
-        
-        if autoreload:
-            def main_module_name():
-                mod = sys.modules['__main__']
-                file = getattr(mod, '__file__', None) # make sure this works even from python interpreter
-                return file and os.path.splitext(os.path.basename(file))[0]
-
-            def modname(fvars):
-                """find name of the module name from fvars."""
-                file, name = fvars.get('__file__'), fvars.get('__name__')
-                if file is None or name is None:
-                    return None
-
-                if name == '__main__':
-                    # Since the __main__ module can't be reloaded, the module has 
-                    # to be imported using its file name.                    
-                    name = main_module_name()
-                return name
-                
-            mapping_name = utils.dictfind(fvars, mapping)
-            module_name = modname(fvars)
-            
-            def reload_mapping():
-                """loadhook to reload mapping and fvars."""
-                mod = __import__(module_name)
-                mapping = getattr(mod, mapping_name, None)
-                if mapping:
-                    self.fvars = mod.__dict__
-                    self.mapping = mapping
-
-            self.add_processor(loadhook(Reloader()))
-            if mapping_name and module_name:
-                self.add_processor(loadhook(reload_mapping))
-
-            # load __main__ module usings its filename, so that it can be reloaded.
-            if main_module_name() and '__main__' in sys.argv:
-                try:
-                    __import__(main_module_name())
-                except ImportError:
-                    pass
-                    
-    def _load(self):
-        web.ctx.app_stack.append(self)
-        
-    def _unload(self):
-        web.ctx.app_stack = web.ctx.app_stack[:-1]
-        
-        if web.ctx.app_stack:
-            # this is a sub-application, revert ctx to earlier state.
-            oldctx = web.ctx.get('_oldctx')
-            if oldctx:
-                web.ctx.home = oldctx.home
-                web.ctx.homepath = oldctx.homepath
-                web.ctx.path = oldctx.path
-                web.ctx.fullpath = oldctx.fullpath
-                
-    def _cleanup(self):
-        #@@@
-        # Since the CherryPy Webserver uses thread pool, the thread-local state is never cleared.
-        # This interferes with the other requests. 
-        # clearing the thread-local storage to avoid that.
-        # see utils.ThreadedDict for details
-        import threading
-        t = threading.currentThread()
-        if hasattr(t, '_d'):
-            del t._d
-    
-    def add_mapping(self, pattern, classname):
-        self.mapping += (pattern, classname)
-        
-    def add_processor(self, processor):
-        """
-        Adds a processor to the application. 
-        
-            >>> urls = ("/(.*)", "echo")
-            >>> app = application(urls, globals())
-            >>> class echo:
-            ...     def GET(self, name): return name
-            ...
-            >>>
-            >>> def hello(handler): return "hello, " +  handler()
-            ...
-            >>> app.add_processor(hello)
-            >>> app.request("/web.py").data
-            'hello, web.py'
-        """
-        self.processors.append(processor)
-
-    def request(self, localpart='/', method='GET', data=None,
-                host="0.0.0.0:8080", headers=None, https=False, **kw):
-        """Makes request to this application for the specified path and method.
-        Response will be a storage object with data, status and headers.
-
-            >>> urls = ("/hello", "hello")
-            >>> app = application(urls, globals())
-            >>> class hello:
-            ...     def GET(self): 
-            ...         web.header('Content-Type', 'text/plain')
-            ...         return "hello"
-            ...
-            >>> response = app.request("/hello")
-            >>> response.data
-            'hello'
-            >>> response.status
-            '200 OK'
-            >>> response.headers['Content-Type']
-            'text/plain'
-
-        To use https, use https=True.
-
-            >>> urls = ("/redirect", "redirect")
-            >>> app = application(urls, globals())
-            >>> class redirect:
-            ...     def GET(self): raise web.seeother("/foo")
-            ...
-            >>> response = app.request("/redirect")
-            >>> response.headers['Location']
-            'http://0.0.0.0:8080/foo'
-            >>> response = app.request("/redirect", https=True)
-            >>> response.headers['Location']
-            'https://0.0.0.0:8080/foo'
-
-        The headers argument specifies HTTP headers as a mapping object
-        such as a dict.
-
-            >>> urls = ('/ua', 'uaprinter')
-            >>> class uaprinter:
-            ...     def GET(self):
-            ...         return 'your user-agent is ' + web.ctx.env['HTTP_USER_AGENT']
-            ... 
-            >>> app = application(urls, globals())
-            >>> app.request('/ua', headers = {
-            ...      'User-Agent': 'a small jumping bean/1.0 (compatible)'
-            ... }).data
-            'your user-agent is a small jumping bean/1.0 (compatible)'
-
-        """
-        path, maybe_query = urllib.splitquery(localpart)
-        query = maybe_query or ""
-        
-        if 'env' in kw:
-            env = kw['env']
-        else:
-            env = {}
-        env = dict(env, HTTP_HOST=host, REQUEST_METHOD=method, PATH_INFO=path, QUERY_STRING=query, HTTPS=str(https))
-        headers = headers or {}
-
-        for k, v in headers.items():
-            env['HTTP_' + k.upper().replace('-', '_')] = v
-
-        if 'HTTP_CONTENT_LENGTH' in env:
-            env['CONTENT_LENGTH'] = env.pop('HTTP_CONTENT_LENGTH')
-
-        if 'HTTP_CONTENT_TYPE' in env:
-            env['CONTENT_TYPE'] = env.pop('HTTP_CONTENT_TYPE')
-
-        if method in ["POST", "PUT"]:
-            data = data or ''
-            import StringIO
-            if isinstance(data, dict):
-                q = urllib.urlencode(data)
-            else:
-                q = data
-            env['wsgi.input'] = StringIO.StringIO(q)
-            if not env.get('CONTENT_TYPE', '').lower().startswith('multipart/') and 'CONTENT_LENGTH' not in env:
-                env['CONTENT_LENGTH'] = len(q)
-        response = web.storage()
-        def start_response(status, headers):
-            response.status = status
-            response.headers = dict(headers)
-            response.header_items = headers
-        response.data = "".join(self.wsgifunc()(env, start_response))
-        return response
-
-    def browser(self):
-        import browser
-        return browser.AppBrowser(self)
-
-    def handle(self):
-        fn, args = self._match(self.mapping, web.ctx.path)
-        return self._delegate(fn, self.fvars, args)
-        
-    def handle_with_processors(self):
-        def process(processors):
-            try:
-                if processors:
-                    p, processors = processors[0], processors[1:]
-                    return p(lambda: process(processors))
-                else:
-                    return self.handle()
-            except web.HTTPError:
-                raise
-            except (KeyboardInterrupt, SystemExit):
-                raise
-            except:
-                print >> web.debug, traceback.format_exc()
-                raise self.internalerror()
-        
-        # processors must be applied in the resvere order. (??)
-        return process(self.processors)
-                        
-    def wsgifunc(self, *middleware):
-        """Returns a WSGI-compatible function for this application."""
-        def peep(iterator):
-            """Peeps into an iterator by doing an iteration
-            and returns an equivalent iterator.
-            """
-            # wsgi requires the headers first
-            # so we need to do an iteration
-            # and save the result for later
-            try:
-                firstchunk = iterator.next()
-            except StopIteration:
-                firstchunk = ''
-
-            return itertools.chain([firstchunk], iterator)    
-                                
-        def is_generator(x): return x and hasattr(x, 'next')
-        
-        def wsgi(env, start_resp):
-            self.load(env)
-            try:
-                # allow uppercase methods only
-                if web.ctx.method.upper() != web.ctx.method:
-                    raise web.nomethod()
-
-                result = self.handle_with_processors()
-                if is_generator(result):
-                    result = peep(result)
-                else:
-                    result = [result]
-            except web.HTTPError, e:
-                result = [e.data]
-
-            result = web.utf8(iter(result))
-
-            status, headers = web.ctx.status, web.ctx.headers
-            start_resp(status, headers)
-            
-            def cleanup():
-                self._cleanup()
-                yield '' # force this function to be a generator
-                            
-            return itertools.chain(result, cleanup())
-
-        for m in middleware: 
-            wsgi = m(wsgi)
-
-        return wsgi
-
-    def run(self, *middleware):
-        """
-        Starts handling requests. If called in a CGI or FastCGI context, it will follow
-        that protocol. If called from the command line, it will start an HTTP
-        server on the port named in the first command line argument, or, if there
-        is no argument, on port 8080.
-        
-        `middleware` is a list of WSGI middleware which is applied to the resulting WSGI
-        function.
-        """
-        return wsgi.runwsgi(self.wsgifunc(*middleware))
-    
-    def cgirun(self, *middleware):
-        """
-        Return a CGI handler. This is mostly useful with Google App Engine.
-        There you can just do:
-        
-            main = app.cgirun()
-        """
-        wsgiapp = self.wsgifunc(*middleware)
-
-        try:
-            from google.appengine.ext.webapp.util import run_wsgi_app
-            return run_wsgi_app(wsgiapp)
-        except ImportError:
-            # we're not running from within Google App Engine
-            return wsgiref.handlers.CGIHandler().run(wsgiapp)
-    
-    def load(self, env):
-        """Initializes ctx using env."""
-        ctx = web.ctx
-        ctx.clear()
-        ctx.status = '200 OK'
-        ctx.headers = []
-        ctx.output = ''
-        ctx.environ = ctx.env = env
-        ctx.host = env.get('HTTP_HOST')
-
-        if env.get('wsgi.url_scheme') in ['http', 'https']:
-            ctx.protocol = env['wsgi.url_scheme']
-        elif env.get('HTTPS', '').lower() in ['on', 'true', '1']:
-            ctx.protocol = 'https'
-        else:
-            ctx.protocol = 'http'
-        ctx.homedomain = ctx.protocol + '://' + env.get('HTTP_HOST', '[unknown]')
-        ctx.homepath = os.environ.get('REAL_SCRIPT_NAME', env.get('SCRIPT_NAME', ''))
-        ctx.home = ctx.homedomain + ctx.homepath
-        #@@ home is changed when the request is handled to a sub-application.
-        #@@ but the real home is required for doing absolute redirects.
-        ctx.realhome = ctx.home
-        ctx.ip = env.get('REMOTE_ADDR')
-        ctx.method = env.get('REQUEST_METHOD')
-        ctx.path = env.get('PATH_INFO')
-        # http://trac.lighttpd.net/trac/ticket/406 requires:
-        if env.get('SERVER_SOFTWARE', '').startswith('lighttpd/'):
-            ctx.path = lstrips(env.get('REQUEST_URI').split('?')[0], ctx.homepath)
-            # Apache and CherryPy webservers unquote the url but lighttpd doesn't. 
-            # unquote explicitly for lighttpd to make ctx.path uniform across all servers.
-            ctx.path = urllib.unquote(ctx.path)
-
-        if env.get('QUERY_STRING'):
-            ctx.query = '?' + env.get('QUERY_STRING', '')
-        else:
-            ctx.query = ''
-
-        ctx.fullpath = ctx.path + ctx.query
-        
-        for k, v in ctx.iteritems():
-            if isinstance(v, str):
-                ctx[k] = safeunicode(v)
-
-        # status must always be str
-        ctx.status = '200 OK'
-        
-        ctx.app_stack = []
-
-    def _delegate(self, f, fvars, args=[]):
-        def handle_class(cls):
-            meth = web.ctx.method
-            if meth == 'HEAD' and not hasattr(cls, meth):
-                meth = 'GET'
-            if not hasattr(cls, meth):
-                raise web.nomethod(cls)
-            tocall = getattr(cls(), meth)
-            return tocall(*args)
-            
-        def is_class(o): return isinstance(o, (types.ClassType, type))
-            
-        if f is None:
-            raise web.notfound()
-        elif isinstance(f, application):
-            return f.handle_with_processors()
-        elif is_class(f):
-            return handle_class(f)
-        elif isinstance(f, basestring):
-            if f.startswith('redirect '):
-                url = f.split(' ', 1)[1]
-                if web.ctx.method == "GET":
-                    x = web.ctx.env.get('QUERY_STRING', '')
-                    if x:
-                        url += '?' + x
-                raise web.redirect(url)
-            elif '.' in f:
-                x = f.split('.')
-                mod, cls = '.'.join(x[:-1]), x[-1]
-                mod = __import__(mod, globals(), locals(), [""])
-                cls = getattr(mod, cls)
-            else:
-                cls = fvars[f]
-            return handle_class(cls)
-        elif hasattr(f, '__call__'):
-            return f()
-        else:
-            return web.notfound()
-
-    def _match(self, mapping, value):
-        for pat, what in utils.group(mapping, 2):
-            if isinstance(what, application):
-                if value.startswith(pat):
-                    f = lambda: self._delegate_sub_application(pat, what)
-                    return f, None
-                else:
-                    continue
-            elif isinstance(what, basestring):
-                what, result = utils.re_subm('^' + pat + '$', what, value)
-            else:
-                result = utils.re_compile('^' + pat + '$').match(value)
-                
-            if result: # it's a match
-                return what, [x for x in result.groups()]
-        return None, None
-        
-    def _delegate_sub_application(self, dir, app):
-        """Deletes request to sub application `app` rooted at the directory `dir`.
-        The home, homepath, path and fullpath values in web.ctx are updated to mimic request
-        to the subapp and are restored after it is handled. 
-        
-        @@Any issues with when used with yield?
-        """
-        web.ctx._oldctx = web.storage(web.ctx)
-        web.ctx.home += dir
-        web.ctx.homepath += dir
-        web.ctx.path = web.ctx.path[len(dir):]
-        web.ctx.fullpath = web.ctx.fullpath[len(dir):]
-        return app.handle_with_processors()
-            
-    def get_parent_app(self):
-        if self in web.ctx.app_stack:
-            index = web.ctx.app_stack.index(self)
-            if index > 0:
-                return web.ctx.app_stack[index-1]
-        
-    def notfound(self):
-        """Returns HTTPError with '404 not found' message"""
-        parent = self.get_parent_app()
-        if parent:
-            return parent.notfound()
-        else:
-            return web._NotFound()
-            
-    def internalerror(self):
-        """Returns HTTPError with '500 internal error' message"""
-        parent = self.get_parent_app()
-        if parent:
-            return parent.internalerror()
-        elif web.config.get('debug'):
-            import debugerror
-            return debugerror.debugerror()
-        else:
-            return web._InternalError()
-
-class auto_application(application):
-    """Application similar to `application` but urls are constructed 
-    automatiacally using metaclass.
-
-        >>> app = auto_application()
-        >>> class hello(app.page):
-        ...     def GET(self): return "hello, world"
-        ...
-        >>> class foo(app.page):
-        ...     path = '/foo/.*'
-        ...     def GET(self): return "foo"
-        >>> app.request("/hello").data
-        'hello, world'
-        >>> app.request('/foo/bar').data
-        'foo'
-    """
-    def __init__(self):
-        application.__init__(self)
-
-        class metapage(type):
-            def __init__(klass, name, bases, attrs):
-                type.__init__(klass, name, bases, attrs)
-                path = attrs.get('path', '/' + name)
-
-                # path can be specified as None to ignore that class
-                # typically required to create a abstract base class.
-                if path is not None:
-                    self.add_mapping(path, klass)
-
-        class page:
-            path = None
-            __metaclass__ = metapage
-
-        self.page = page
-
-# The application class already has the required functionality of subdir_application
-subdir_application = application
-                
-class subdomain_application(application):
-    """
-    Application to delegate requests based on the host.
-
-        >>> urls = ("/hello", "hello")
-        >>> app = application(urls, globals())
-        >>> class hello:
-        ...     def GET(self): return "hello"
-        >>>
-        >>> mapping = (r"hello\.example\.com", app)
-        >>> app2 = subdomain_application(mapping)
-        >>> app2.request("/hello", host="hello.example.com").data
-        'hello'
-        >>> response = app2.request("/hello", host="something.example.com")
-        >>> response.status
-        '404 Not Found'
-        >>> response.data
-        'not found'
-    """
-    def handle(self):
-        host = web.ctx.host.split(':')[0] #strip port
-        fn, args = self._match(self.mapping, host)
-        return self._delegate(fn, self.fvars, args)
-        
-    def _match(self, mapping, value):
-        for pat, what in utils.group(mapping, 2):
-            if isinstance(what, basestring):
-                what, result = utils.re_subm('^' + pat + '$', what, value)
-            else:
-                result = utils.re_compile('^' + pat + '$').match(value)
-
-            if result: # it's a match
-                return what, [x for x in result.groups()]
-        return None, None
-        
-def loadhook(h):
-    """
-    Converts a load hook into an application processor.
-    
-        >>> app = auto_application()
-        >>> def f(): "something done before handling request"
-        ...
-        >>> app.add_processor(loadhook(f))
-    """
-    def processor(handler):
-        h()
-        return handler()
-        
-    return processor
-    
-def unloadhook(h):
-    """
-    Converts an unload hook into an application processor.
-    
-        >>> app = auto_application()
-        >>> def f(): "something done after handling request"
-        ...
-        >>> app.add_processor(unloadhook(f))    
-    """
-    def processor(handler):
-        try:
-            result = handler()
-            is_generator = result and hasattr(result, 'next')
-        except:
-            # run the hook even when handler raises some exception
-            h()
-            raise
-
-        if is_generator:
-            return wrap(result)
-        else:
-            h()
-            return result
-            
-    def wrap(result):
-        def next():
-            try:
-                return result.next()
-            except:
-                # call the hook at the and of iterator
-                h()
-                raise
-
-        result = iter(result)
-        while True:
-            yield next()
-            
-    return processor
-
-def autodelegate(prefix=''):
-    """
-    Returns a method that takes one argument and calls the method named prefix+arg,
-    calling `notfound()` if there isn't one. Example:
-
-        urls = ('/prefs/(.*)', 'prefs')
-
-        class prefs:
-            GET = autodelegate('GET_')
-            def GET_password(self): pass
-            def GET_privacy(self): pass
-
-    `GET_password` would get called for `/prefs/password` while `GET_privacy` for 
-    `GET_privacy` gets called for `/prefs/privacy`.
-    
-    If a user visits `/prefs/password/change` then `GET_password(self, '/change')`
-    is called.
-    """
-    def internal(self, arg):
-        if '/' in arg:
-            first, rest = arg.split('/', 1)
-            func = prefix + first
-            args = ['/' + rest]
-        else:
-            func = prefix + arg
-            args = []
-        
-        if hasattr(self, func):
-            try:
-                return getattr(self, func)(*args)
-            except TypeError:
-                return web.notfound()
-        else:
-            return web.notfound()
-    return internal
-
-class Reloader:
-    """Checks to see if any loaded modules have changed on disk and, 
-    if so, reloads them.
-    """
-    def __init__(self):
-        self.mtimes = {}
-
-    def __call__(self):
-        for mod in sys.modules.values():
-            self.check(mod)
-            
-    def check(self, mod):
-        try: 
-            mtime = os.stat(mod.__file__).st_mtime
-        except (AttributeError, OSError, IOError):
-            return
-        if mod.__file__.endswith('.pyc') and os.path.exists(mod.__file__[:-1]):
-            mtime = max(os.stat(mod.__file__[:-1]).st_mtime, mtime)
-            
-        if mod not in self.mtimes:
-            self.mtimes[mod] = mtime
-        elif self.mtimes[mod] < mtime:
-            try: 
-                reload(mod)
-                self.mtimes[mod] = mtime
-            except ImportError: 
-                pass
-                
-if __name__ == "__main__":
-    import doctest
-    doctest.testmod()
--- a/bundled/webpy/web/browser.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,236 +0,0 @@
-"""Browser to test web applications.
-(from web.py)
-"""
-from utils import re_compile
-from net import htmlunquote
-
-import httplib, urllib, urllib2
-import copy
-from StringIO import StringIO
-
-DEBUG = False
-
-__all__ = [
-    "BrowserError",
-    "Browser", "AppBrowser",
-    "AppHandler"
-]
-
-class BrowserError(Exception):
-    pass
-
-class Browser:
-    def __init__(self):
-        import cookielib
-        self.cookiejar = cookielib.CookieJar()
-        self._cookie_processor = urllib2.HTTPCookieProcessor(self.cookiejar)
-        self.form = None
-
-        self.url = "http://0.0.0.0:8080/"
-        self.path = "/"
-        
-        self.status = None
-        self.data = None
-        self._response = None
-        self._forms = None
-
-    def reset(self):
-        """Clears all cookies and history."""
-        self.cookiejar.clear()
-
-    def build_opener(self):
-        """Builds the opener using urllib2.build_opener. 
-        Subclasses can override this function to prodive custom openers.
-        """
-        return urllib2.build_opener()
-
-    def do_request(self, req):
-        if DEBUG:
-            print 'requesting', req.get_method(), req.get_full_url()
-        opener = self.build_opener()
-        opener.add_handler(self._cookie_processor)
-        try:
-            self._response = opener.open(req)
-        except urllib2.HTTPError, e:
-            self._response = e
-
-        self.url = self._response.geturl()
-        self.path = urllib2.Request(self.url).get_selector()
-        self.data = self._response.read()
-        self.status = self._response.code
-        self._forms = None
-        self.form = None
-        return self.get_response()
-
-    def open(self, url, data=None, headers={}):
-        """Opens the specified url."""
-        url = urllib.basejoin(self.url, url)
-        req = urllib2.Request(url, data, headers)
-        return self.do_request(req)
-
-    def show(self):
-        """Opens the current page in real web browser."""
-        f = open('page.html', 'w')
-        f.write(self.data)
-        f.close()
-
-        import webbrowser, os
-        url = 'file://' + os.path.abspath('page.html')
-        webbrowser.open(url)
-
-    def get_response(self):
-        """Returns a copy of the current response."""
-        return urllib.addinfourl(StringIO(self.data), self._response.info(), self._response.geturl())
-
-    def get_soup(self):
-        """Returns beautiful soup of the current document."""
-        import BeautifulSoup
-        return BeautifulSoup.BeautifulSoup(self.data)
-
-    def get_text(self, e=None):
-        """Returns content of e or the current document as plain text."""
-        e = e or self.get_soup()
-        return ''.join([htmlunquote(c) for c in e.recursiveChildGenerator() if isinstance(c, unicode)])
-
-    def _get_links(self):
-        soup = self.get_soup()
-        return [a for a in soup.findAll(name='a')]
-        
-    def get_links(self, text=None, text_regex=None, url=None, url_regex=None, predicate=None):
-        """Returns all links in the document."""
-        return self._filter_links(self._get_links(),
-            text=text, text_regex=text_regex, url=url, url_regex=url_regex, predicate=predicate)
-
-    def follow_link(self, link=None, text=None, text_regex=None, url=None, url_regex=None, predicate=None):
-        if link is None:
-            links = self._filter_links(self.get_links(),
-                text=text, text_regex=text_regex, url=url, url_regex=url_regex, predicate=predicate)
-            link = links and links[0]
-            
-        if link:
-            return self.open(link['href'])
-        else:
-            raise BrowserError("No link found")
-            
-    def find_link(self, text=None, text_regex=None, url=None, url_regex=None, predicate=None):
-        links = self._filter_links(self.get_links(), 
-            text=text, text_regex=text_regex, url=url, url_regex=url_regex, predicate=predicate)
-        return links and links[0] or None
-            
-    def _filter_links(self, links, 
-            text=None, text_regex=None,
-            url=None, url_regex=None,
-            predicate=None):
-        predicates = []
-        if text is not None:
-            predicates.append(lambda link: link.string == text)
-        if text_regex is not None:
-            predicates.append(lambda link: re_compile(text_regex).search(link.string or ''))
-        if url is not None:
-            predicates.append(lambda link: link.get('href') == url)
-        if url_regex is not None:
-            predicates.append(lambda link: re_compile(url_regex).search(link.get('href', '')))
-        if predicate:
-            predicate.append(predicate)
-
-        def f(link):
-            for p in predicates:
-                if not p(link):
-                    return False
-            return True
-
-        return [link for link in links if f(link)]
-
-    def get_forms(self):
-        """Returns all forms in the current document.
-        The returned form objects implement the ClientForm.HTMLForm interface.
-        """
-        if self._forms is None:
-            import ClientForm
-            self._forms = ClientForm.ParseResponse(self.get_response(), backwards_compat=False)
-        return self._forms
-
-    def select_form(self, name=None, predicate=None, index=0):
-        """Selects the specified form."""
-        forms = self.get_forms()
-
-        if name is not None:
-            forms = [f for f in forms if f.name == name]
-        if predicate:
-            forms = [f for f in forms if predicate(f)]
-            
-        if forms:
-            self.form = forms[index]
-            return self.form
-        else:
-            raise BrowserError("No form selected.")
-        
-    def submit(self, **kw):
-        """submits the currently selected form."""
-        if self.form is None:
-            raise BrowserError("No form selected.")
-        req = self.form.click(**kw)
-        return self.do_request(req)
-
-    def __getitem__(self, key):
-        return self.form[key]
-
-    def __setitem__(self, key, value):
-        self.form[key] = value
-
-class AppBrowser(Browser):
-    """Browser interface to test web.py apps.
-    
-        b = AppBrowser(app)
-        b.open('/')
-        b.follow_link(text='Login')
-        
-        b.select_form(name='login')
-        b['username'] = 'joe'
-        b['password'] = 'secret'
-        b.submit()
-
-        assert b.path == '/'
-        assert 'Welcome joe' in b.get_text()
-    """
-    def __init__(self, app):
-        Browser.__init__(self)
-        self.app = app
-
-    def build_opener(self):
-        return urllib2.build_opener(AppHandler(self.app))
-
-class AppHandler(urllib2.HTTPHandler):
-    """urllib2 handler to handle requests using web.py application."""
-    handler_order = 100
-
-    def __init__(self, app):
-        self.app = app
-
-    def http_open(self, req):
-        result = self.app.request(
-            localpart=req.get_selector(),
-            method=req.get_method(),
-            host=req.get_host(),
-            data=req.get_data(),
-            headers=dict(req.header_items()),
-            https=req.get_type() == "https"
-        )
-        return self._make_response(result, req.get_full_url())
-
-    def https_open(self, req):
-        return self.http_open(req)
-    
-    try:
-        https_request = urllib2.HTTPHandler.do_request_
-    except AttributeError:
-        # for python 2.3
-        pass
-
-    def _make_response(self, result, url):
-        data = "\r\n".join(["%s: %s" % (k, v) for k, v in result.header_items])
-        headers = httplib.HTTPMessage(StringIO(data))
-        response = urllib.addinfourl(StringIO(result.data), headers, url)
-        code, msg = result.status.split(None, 1)
-        response.code, response.msg = int(code), msg
-        return response
--- a/bundled/webpy/web/contrib/template.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,131 +0,0 @@
-"""
-Interface to various templating engines.
-"""
-import os.path
-
-__all__ = [
-    "render_cheetah", "render_genshi", "render_mako",
-    "cache", 
-]
-
-class render_cheetah:
-    """Rendering interface to Cheetah Templates.
-
-    Example:
-
-        render = render_cheetah('templates')
-        render.hello(name="cheetah")
-    """
-    def __init__(self, path):
-        # give error if Chetah is not installed
-        from Cheetah.Template import Template
-        self.path = path
-
-    def __getattr__(self, name):
-        from Cheetah.Template import Template
-        path = os.path.join(self.path, name + ".html")
-        
-        def template(**kw):
-            t = Template(file=path, searchList=[kw])
-            return t.respond()
-
-        return template
-    
-class render_genshi:
-    """Rendering interface genshi templates.
-    Example:
-
-    for xml/html templates.
-
-        render = render_genshi(['templates/'])
-        render.hello(name='genshi')
-
-    For text templates:
-
-        render = render_genshi(['templates/'], type='text')
-        render.hello(name='genshi')
-    """
-
-    def __init__(self, *a, **kwargs):
-        from genshi.template import TemplateLoader
-
-        self._type = kwargs.pop('type', None)
-        self._loader = TemplateLoader(*a, **kwargs)
-
-    def __getattr__(self, name):
-        # Assuming all templates are html
-        path = name + ".html"
-
-        if self._type == "text":
-            from genshi.template import TextTemplate
-            cls = TextTemplate
-            type = "text"
-        else:
-            cls = None
-            type = None
-
-        t = self._loader.load(path, cls=cls)
-        def template(**kw):
-            stream = t.generate(**kw)
-            if type:
-                return stream.render(type)
-            else:
-                return stream.render()
-        return template
-
-class render_jinja:
-    """Rendering interface to Jinja2 Templates
-    
-    Example:
-
-        render= render_jinja('templates')
-        render.hello(name='jinja2')
-    """
-    def __init__(self, *a, **kwargs):
-        extensions = kwargs.pop('extensions', [])
-        globals = kwargs.pop('globals', {})
-
-        from jinja2 import Environment,FileSystemLoader
-        self._lookup = Environment(loader=FileSystemLoader(*a, **kwargs), extensions=extensions)
-        self._lookup.globals.update(globals)
-        
-    def __getattr__(self, name):
-        # Assuming all templates end with .html
-        path = name + '.html'
-        t = self._lookup.get_template(path)
-        return t.render
-        
-class render_mako:
-    """Rendering interface to Mako Templates.
-
-    Example:
-
-        render = render_mako(directories=['templates'])
-        render.hello(name="mako")
-    """
-    def __init__(self, *a, **kwargs):
-        from mako.lookup import TemplateLookup
-        self._lookup = TemplateLookup(*a, **kwargs)
-
-    def __getattr__(self, name):
-        # Assuming all templates are html
-        path = name + ".html"
-        t = self._lookup.get_template(path)
-        return t.render
-
-class cache:
-    """Cache for any rendering interface.
-    
-    Example:
-
-        render = cache(render_cheetah("templates/"))
-        render.hello(name='cache')
-    """
-    def __init__(self, render):
-        self._render = render
-        self._cache = {}
-
-    def __getattr__(self, name):
-        if name not in self._cache:
-            self._cache[name] = getattr(self._render, name)
-        return self._cache[name]
--- a/bundled/webpy/web/db.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1137 +0,0 @@
-"""
-Database API
-(part of web.py)
-"""
-
-__all__ = [
-  "UnknownParamstyle", "UnknownDB", "TransactionError", 
-  "sqllist", "sqlors", "reparam", "sqlquote",
-  "SQLQuery", "SQLParam", "sqlparam",
-  "SQLLiteral", "sqlliteral",
-  "database", 'DB',
-]
-
-import time
-try:
-    import datetime
-except ImportError:
-    datetime = None
-
-from utils import threadeddict, storage, iters, iterbetter
-
-try:
-    # db module can work independent of web.py
-    from webapi import debug, config
-except:
-    import sys
-    debug = sys.stderr
-    config = storage()
-
-class UnknownDB(Exception):
-    """raised for unsupported dbms"""
-    pass
-
-class _ItplError(ValueError): 
-    def __init__(self, text, pos):
-        ValueError.__init__(self)
-        self.text = text
-        self.pos = pos
-    def __str__(self):
-        return "unfinished expression in %s at char %d" % (
-            repr(self.text), self.pos)
-
-class TransactionError(Exception): pass
-
-class UnknownParamstyle(Exception): 
-    """
-    raised for unsupported db paramstyles
-
-    (currently supported: qmark, numeric, format, pyformat)
-    """
-    pass
-    
-class SQLParam:
-    """
-    Parameter in SQLQuery.
-    
-        >>> q = SQLQuery(["SELECT * FROM test WHERE name=", SQLParam("joe")])
-        >>> q
-        <sql: "SELECT * FROM test WHERE name='joe'">
-        >>> q.query()
-        'SELECT * FROM test WHERE name=%s'
-        >>> q.values()
-        ['joe']
-    """
-    def __init__(self, value):
-        self.value = value
-        
-    def get_marker(self, paramstyle='pyformat'):
-        if paramstyle == 'qmark':
-            return '?'
-        elif paramstyle == 'numeric':
-            return ':1'
-        elif paramstyle is None or paramstyle in ['format', 'pyformat']:
-            return '%s'
-        raise UnknownParamstyle, paramstyle
-        
-    def sqlquery(self): 
-        return SQLQuery([self])
-        
-    def __add__(self, other):
-        return self.sqlquery() + other
-        
-    def __radd__(self, other):
-        return other + self.sqlquery() 
-            
-    def __str__(self): 
-        return str(self.value)
-    
-    def __repr__(self):
-        return '<param: %s>' % repr(self.value)
-
-sqlparam =  SQLParam
-
-class SQLQuery:
-    """
-    You can pass this sort of thing as a clause in any db function.
-    Otherwise, you can pass a dictionary to the keyword argument `vars`
-    and the function will call reparam for you.
-
-    Internally, consists of `items`, which is a list of strings and
-    SQLParams, which get concatenated to produce the actual query.
-    """
-    # tested in sqlquote's docstring
-    def __init__(self, items=[]):
-        """Creates a new SQLQuery.
-        
-            >>> SQLQuery("x")
-            <sql: 'x'>
-            >>> q = SQLQuery(['SELECT * FROM ', 'test', ' WHERE x=', SQLParam(1)])
-            >>> q
-            <sql: 'SELECT * FROM test WHERE x=1'>
-            >>> q.query(), q.values()
-            ('SELECT * FROM test WHERE x=%s', [1])
-            >>> SQLQuery(SQLParam(1))
-            <sql: '1'>
-        """
-        if isinstance(items, list):
-            self.items = items
-        elif isinstance(items, SQLParam):
-            self.items = [items]
-        elif isinstance(items, SQLQuery):
-            self.items = list(items.items)
-        else:
-            self.items = [str(items)]
-            
-        # Take care of SQLLiterals
-        for i, item in enumerate(self.items):
-            if isinstance(item, SQLParam) and isinstance(item.value, SQLLiteral):
-                self.items[i] = item.value.v
-
-    def __add__(self, other):
-        if isinstance(other, basestring):
-            items = [other]
-        elif isinstance(other, SQLQuery):
-            items = other.items
-        else:
-            return NotImplemented
-        return SQLQuery(self.items + items)
-
-    def __radd__(self, other):
-        if isinstance(other, basestring):
-            items = [other]
-        else:
-            return NotImplemented
-            
-        return SQLQuery(items + self.items)
-
-    def __iadd__(self, other):
-        if isinstance(other, basestring):
-            items = [other]
-        elif isinstance(other, SQLQuery):
-            items = other.items
-        else:
-            return NotImplemented
-        self.items.extend(items)
-        return self
-
-    def __len__(self):
-        return len(self.query())
-        
-    def query(self, paramstyle=None):
-        """
-        Returns the query part of the sql query.
-            >>> q = SQLQuery(["SELECT * FROM test WHERE name=", SQLParam('joe')])
-            >>> q.query()
-            'SELECT * FROM test WHERE name=%s'
-            >>> q.query(paramstyle='qmark')
-            'SELECT * FROM test WHERE name=?'
-        """
-        s = ''
-        for x in self.items:
-            if isinstance(x, SQLParam):
-                x = x.get_marker(paramstyle)
-            s += x
-        return s
-    
-    def values(self):
-        """
-        Returns the values of the parameters used in the sql query.
-            >>> q = SQLQuery(["SELECT * FROM test WHERE name=", SQLParam('joe')])
-            >>> q.values()
-            ['joe']
-        """
-        return [i.value for i in self.items if isinstance(i, SQLParam)]
-        
-    def join(items, sep=' '):
-        """
-        Joins multiple queries.
-        
-        >>> SQLQuery.join(['a', 'b'], ', ')
-        <sql: 'a, b'>
-        """
-        if len(items) == 0:
-            return SQLQuery("")
-
-        q = SQLQuery(items[0])
-        for item in items[1:]:
-            q += sep
-            q += item
-        return q
-    
-    join = staticmethod(join)
-
-    def __str__(self):
-        try:
-            return self.query() % tuple([sqlify(x) for x in self.values()])
-        except (ValueError, TypeError):
-            return self.query()
-
-    def __repr__(self):
-        return '<sql: %s>' % repr(str(self))
-
-class SQLLiteral: 
-    """
-    Protects a string from `sqlquote`.
-
-        >>> sqlquote('NOW()')
-        <sql: "'NOW()'">
-        >>> sqlquote(SQLLiteral('NOW()'))
-        <sql: 'NOW()'>
-    """
-    def __init__(self, v): 
-        self.v = v
-
-    def __repr__(self): 
-        return self.v
-
-sqlliteral = SQLLiteral
-
-def _sqllist(values):
-    """
-        >>> _sqllist([1, 2, 3])
-        <sql: '(1, 2, 3)'>
-    """
-    items = []
-    items.append('(')
-    for i, v in enumerate(values):
-        if i != 0:
-            items.append(', ')
-        items.append(sqlparam(v))
-    items.append(')')
-    return SQLQuery(items)
-
-def reparam(string_, dictionary): 
-    """
-    Takes a string and a dictionary and interpolates the string
-    using values from the dictionary. Returns an `SQLQuery` for the result.
-
-        >>> reparam("s = $s", dict(s=True))
-        <sql: "s = 't'">
-        >>> reparam("s IN $s", dict(s=[1, 2]))
-        <sql: 's IN (1, 2)'>
-    """
-    dictionary = dictionary.copy() # eval mucks with it
-    vals = []
-    result = []
-    for live, chunk in _interpolate(string_):
-        if live:
-            v = eval(chunk, dictionary)
-            result.append(sqlquote(v))
-        else: 
-            result.append(chunk)
-    return SQLQuery.join(result, '')
-
-def sqlify(obj): 
-    """
-    converts `obj` to its proper SQL version
-
-        >>> sqlify(None)
-        'NULL'
-        >>> sqlify(True)
-        "'t'"
-        >>> sqlify(3)
-        '3'
-    """
-    # because `1 == True and hash(1) == hash(True)`
-    # we have to do this the hard way...
-
-    if obj is None:
-        return 'NULL'
-    elif obj is True:
-        return "'t'"
-    elif obj is False:
-        return "'f'"
-    elif datetime and isinstance(obj, datetime.datetime):
-        return repr(obj.isoformat())
-    else:
-        return repr(obj)
-
-def sqllist(lst): 
-    """
-    Converts the arguments for use in something like a WHERE clause.
-    
-        >>> sqllist(['a', 'b'])
-        'a, b'
-        >>> sqllist('a')
-        'a'
-        >>> sqllist(u'abc')
-        u'abc'
-    """
-    if isinstance(lst, basestring): 
-        return lst
-    else:
-        return ', '.join(lst)
-
-def sqlors(left, lst):
-    """
-    `left is a SQL clause like `tablename.arg = ` 
-    and `lst` is a list of values. Returns a reparam-style
-    pair featuring the SQL that ORs together the clause
-    for each item in the lst.
-
-        >>> sqlors('foo = ', [])
-        <sql: '1=2'>
-        >>> sqlors('foo = ', [1])
-        <sql: 'foo = 1'>
-        >>> sqlors('foo = ', 1)
-        <sql: 'foo = 1'>
-        >>> sqlors('foo = ', [1,2,3])
-        <sql: '(foo = 1 OR foo = 2 OR foo = 3 OR 1=2)'>
-    """
-    if isinstance(lst, iters):
-        lst = list(lst)
-        ln = len(lst)
-        if ln == 0:
-            return SQLQuery("1=2")
-        if ln == 1:
-            lst = lst[0]
-
-    if isinstance(lst, iters):
-        return SQLQuery(['('] + 
-          sum([[left, sqlparam(x), ' OR '] for x in lst], []) +
-          ['1=2)']
-        )
-    else:
-        return left + sqlparam(lst)
-        
-def sqlwhere(dictionary, grouping=' AND '): 
-    """
-    Converts a `dictionary` to an SQL WHERE clause `SQLQuery`.
-    
-        >>> sqlwhere({'cust_id': 2, 'order_id':3})
-        <sql: 'order_id = 3 AND cust_id = 2'>
-        >>> sqlwhere({'cust_id': 2, 'order_id':3}, grouping=', ')
-        <sql: 'order_id = 3, cust_id = 2'>
-        >>> sqlwhere({'a': 'a', 'b': 'b'}).query()
-        'a = %s AND b = %s'
-    """
-    return SQLQuery.join([k + ' = ' + sqlparam(v) for k, v in dictionary.items()], grouping)
-
-def sqlquote(a): 
-    """
-    Ensures `a` is quoted properly for use in a SQL query.
-
-        >>> 'WHERE x = ' + sqlquote(True) + ' AND y = ' + sqlquote(3)
-        <sql: "WHERE x = 't' AND y = 3">
-        >>> 'WHERE x = ' + sqlquote(True) + ' AND y IN ' + sqlquote([2, 3])
-        <sql: "WHERE x = 't' AND y IN (2, 3)">
-    """
-    if isinstance(a, list):
-        return _sqllist(a)
-    else:
-        return sqlparam(a).sqlquery()
-
-class Transaction:
-    """Database transaction."""
-    def __init__(self, ctx):
-        self.ctx = ctx
-        self.transaction_count = transaction_count = len(ctx.transactions)
-
-        class transaction_engine:
-            """Transaction Engine used in top level transactions."""
-            def do_transact(self):
-                ctx.commit(unload=False)
-
-            def do_commit(self):
-                ctx.commit()
-
-            def do_rollback(self):
-                ctx.rollback()
-
-        class subtransaction_engine:
-            """Transaction Engine used in sub transactions."""
-            def query(self, q):
-                db_cursor = ctx.db.cursor()
-                ctx.db_execute(db_cursor, SQLQuery(q % transaction_count))
-
-            def do_transact(self):
-                self.query('SAVEPOINT webpy_sp_%s')
-
-            def do_commit(self):
-                self.query('RELEASE SAVEPOINT webpy_sp_%s')
-
-            def do_rollback(self):
-                self.query('ROLLBACK TO SAVEPOINT webpy_sp_%s')
-
-        class dummy_engine:
-            """Transaction Engine used instead of subtransaction_engine 
-            when sub transactions are not supported."""
-            do_transact = do_commit = do_rollback = lambda self: None
-
-        if self.transaction_count:
-            # nested transactions are not supported in some databases
-            if self.ctx.get('ignore_nested_transactions'):
-                self.engine = dummy_engine()
-            else:
-                self.engine = subtransaction_engine()
-        else:
-            self.engine = transaction_engine()
-
-        self.engine.do_transact()
-        self.ctx.transactions.append(self)
-
-    def __enter__(self):
-        return self
-
-    def __exit__(self, exctype, excvalue, traceback):
-        if exctype is not None:
-            self.rollback()
-        else:
-            self.commit()
-
-    def commit(self):
-        if len(self.ctx.transactions) > self.transaction_count:
-            self.engine.do_commit()
-            self.ctx.transactions = self.ctx.transactions[:self.transaction_count]
-
-    def rollback(self):
-        if len(self.ctx.transactions) > self.transaction_count:
-            self.engine.do_rollback()
-            self.ctx.transactions = self.ctx.transactions[:self.transaction_count]
-
-class DB: 
-    """Database"""
-    def __init__(self, db_module, keywords):
-        """Creates a database.
-        """
-        # some DB implementaions take optional paramater `driver` to use a specific driver modue
-        # but it should not be passed to connect
-        keywords.pop('driver', None)
-
-        self.db_module = db_module
-        self.keywords = keywords
-
-        
-        self._ctx = threadeddict()
-        # flag to enable/disable printing queries
-        self.printing = config.get('debug', False)
-        self.supports_multiple_insert = False
-        
-        try:
-            import DBUtils
-            # enable pooling if DBUtils module is available.
-            self.has_pooling = True
-        except ImportError:
-            self.has_pooling = False
-            
-        # Pooling can be disabled by passing pooling=False in the keywords.
-        self.has_pooling = self.keywords.pop('pooling', True) and self.has_pooling
-            
-    def _getctx(self): 
-        if not self._ctx.get('db'):
-            self._load_context(self._ctx)
-        return self._ctx
-    ctx = property(_getctx)
-    
-    def _load_context(self, ctx):
-        ctx.dbq_count = 0
-        ctx.transactions = [] # stack of transactions
-        
-        if self.has_pooling:
-            ctx.db = self._connect_with_pooling(self.keywords)
-        else:
-            ctx.db = self._connect(self.keywords)
-        ctx.db_execute = self._db_execute
-        
-        if not hasattr(ctx.db, 'commit'):
-            ctx.db.commit = lambda: None
-
-        if not hasattr(ctx.db, 'rollback'):
-            ctx.db.rollback = lambda: None
-            
-        def commit(unload=True):
-            # do db commit and release the connection if pooling is enabled.            
-            ctx.db.commit()
-            if unload and self.has_pooling:
-                self._unload_context(self._ctx)
-                
-        def rollback():
-            # do db rollback and release the connection if pooling is enabled.
-            ctx.db.rollback()
-            if self.has_pooling:
-                self._unload_context(self._ctx)
-                
-        ctx.commit = commit
-        ctx.rollback = rollback
-            
-    def _unload_context(self, ctx):
-        del ctx.db
-            
-    def _connect(self, keywords):
-        return self.db_module.connect(**keywords)
-        
-    def _connect_with_pooling(self, keywords):
-        def get_pooled_db():
-            from DBUtils import PooledDB
-
-            # In DBUtils 0.9.3, `dbapi` argument is renamed as `creator`
-            # see Bug#122112
-            
-            if PooledDB.__version__.split('.') < '0.9.3'.split('.'):
-                return PooledDB.PooledDB(dbapi=self.db_module, **keywords)
-            else:
-                return PooledDB.PooledDB(creator=self.db_module, **keywords)
-        
-        if getattr(self, '_pooleddb', None) is None:
-            self._pooleddb = get_pooled_db()
-        
-        return self._pooleddb.connection()
-        
-    def _db_cursor(self):
-        return self.ctx.db.cursor()
-
-    def _param_marker(self):
-        """Returns parameter marker based on paramstyle attribute if this database."""
-        style = getattr(self, 'paramstyle', 'pyformat')
-
-        if style == 'qmark':
-            return '?'
-        elif style == 'numeric':
-            return ':1'
-        elif style in ['format', 'pyformat']:
-            return '%s'
-        raise UnknownParamstyle, style
-
-    def _db_execute(self, cur, sql_query): 
-        """executes an sql query"""
-        self.ctx.dbq_count += 1
-        
-        try:
-            a = time.time()
-            paramstyle = getattr(self, 'paramstyle', 'pyformat')
-            out = cur.execute(sql_query.query(paramstyle), sql_query.values())
-            b = time.time()
-        except:
-            if self.printing:
-                print >> debug, 'ERR:', str(sql_query)
-            if self.ctx.transactions:
-                self.ctx.transactions[-1].rollback()
-            else:
-                self.ctx.rollback()
-            raise
-
-        if self.printing:
-            print >> debug, '%s (%s): %s' % (round(b-a, 2), self.ctx.dbq_count, str(sql_query))
-        return out
-    
-    def _where(self, where, vars): 
-        if isinstance(where, (int, long)):
-            where = "id = " + sqlparam(where)
-        #@@@ for backward-compatibility
-        elif isinstance(where, (list, tuple)) and len(where) == 2:
-            where = SQLQuery(where[0], where[1])
-        elif isinstance(where, SQLQuery):
-            pass
-        else:
-            where = reparam(where, vars)        
-        return where
-    
-    def query(self, sql_query, vars=None, processed=False, _test=False): 
-        """
-        Execute SQL query `sql_query` using dictionary `vars` to interpolate it.
-        If `processed=True`, `vars` is a `reparam`-style list to use 
-        instead of interpolating.
-        
-            >>> db = DB(None, {})
-            >>> db.query("SELECT * FROM foo", _test=True)
-            <sql: 'SELECT * FROM foo'>
-            >>> db.query("SELECT * FROM foo WHERE x = $x", vars=dict(x='f'), _test=True)
-            <sql: "SELECT * FROM foo WHERE x = 'f'">
-            >>> db.query("SELECT * FROM foo WHERE x = " + sqlquote('f'), _test=True)
-            <sql: "SELECT * FROM foo WHERE x = 'f'">
-        """
-        if vars is None: vars = {}
-        
-        if not processed and not isinstance(sql_query, SQLQuery):
-            sql_query = reparam(sql_query, vars)
-        
-        if _test: return sql_query
-        
-        db_cursor = self._db_cursor()
-        self._db_execute(db_cursor, sql_query)
-        
-        if db_cursor.description:
-            names = [x[0] for x in db_cursor.description]
-            def iterwrapper():
-                row = db_cursor.fetchone()
-                while row:
-                    yield storage(dict(zip(names, row)))
-                    row = db_cursor.fetchone()
-            out = iterbetter(iterwrapper())
-            out.__len__ = lambda: int(db_cursor.rowcount)
-            out.list = lambda: [storage(dict(zip(names, x))) \
-                               for x in db_cursor.fetchall()]
-        else:
-            out = db_cursor.rowcount
-        
-        if not self.ctx.transactions: 
-            self.ctx.commit()
-        return out
-    
-    def select(self, tables, vars=None, what='*', where=None, order=None, group=None, 
-               limit=None, offset=None, _test=False): 
-        """
-        Selects `what` from `tables` with clauses `where`, `order`, 
-        `group`, `limit`, and `offset`. Uses vars to interpolate. 
-        Otherwise, each clause can be a SQLQuery.
-        
-            >>> db = DB(None, {})
-            >>> db.select('foo', _test=True)
-            <sql: 'SELECT * FROM foo'>
-            >>> db.select(['foo', 'bar'], where="foo.bar_id = bar.id", limit=5, _test=True)
-            <sql: 'SELECT * FROM foo, bar WHERE foo.bar_id = bar.id LIMIT 5'>
-        """
-        if vars is None: vars = {}
-        sql_clauses = self.sql_clauses(what, tables, where, group, order, limit, offset)
-        clauses = [self.gen_clause(sql, val, vars) for sql, val in sql_clauses if val is not None]
-        qout = SQLQuery.join(clauses)
-        if _test: return qout
-        return self.query(qout, processed=True)
-    
-    def where(self, table, what='*', order=None, group=None, limit=None, 
-              offset=None, _test=False, **kwargs):
-        """
-        Selects from `table` where keys are equal to values in `kwargs`.
-        
-            >>> db = DB(None, {})
-            >>> db.where('foo', bar_id=3, _test=True)
-            <sql: 'SELECT * FROM foo WHERE bar_id = 3'>
-            >>> db.where('foo', source=2, crust='dewey', _test=True)
-            <sql: "SELECT * FROM foo WHERE source = 2 AND crust = 'dewey'">
-        """
-        where = []
-        for k, v in kwargs.iteritems():
-            where.append(k + ' = ' + sqlquote(v))
-        return self.select(table, what=what, order=order, 
-               group=group, limit=limit, offset=offset, _test=_test, 
-               where=SQLQuery.join(where, ' AND '))
-    
-    def sql_clauses(self, what, tables, where, group, order, limit, offset): 
-        return (
-            ('SELECT', what),
-            ('FROM', sqllist(tables)),
-            ('WHERE', where),
-            ('GROUP BY', group),
-            ('ORDER BY', order),
-            ('LIMIT', limit),
-            ('OFFSET', offset))
-    
-    def gen_clause(self, sql, val, vars): 
-        if isinstance(val, (int, long)):
-            if sql == 'WHERE':
-                nout = 'id = ' + sqlquote(val)
-            else:
-                nout = SQLQuery(val)
-        #@@@
-        elif isinstance(val, (list, tuple)) and len(val) == 2:
-            nout = SQLQuery(val[0], val[1]) # backwards-compatibility
-        elif isinstance(val, SQLQuery):
-            nout = val
-        else:
-            nout = reparam(val, vars)
-
-        def xjoin(a, b):
-            if a and b: return a + ' ' + b
-            else: return a or b
-
-        return xjoin(sql, nout)
-
-    def insert(self, tablename, seqname=None, _test=False, **values): 
-        """
-        Inserts `values` into `tablename`. Returns current sequence ID.
-        Set `seqname` to the ID if it's not the default, or to `False`
-        if there isn't one.
-        
-            >>> db = DB(None, {})
-            >>> q = db.insert('foo', name='bob', age=2, created=SQLLiteral('NOW()'), _test=True)
-            >>> q
-            <sql: "INSERT INTO foo (age, name, created) VALUES (2, 'bob', NOW())">
-            >>> q.query()
-            'INSERT INTO foo (age, name, created) VALUES (%s, %s, NOW())'
-            >>> q.values()
-            [2, 'bob']
-        """
-        def q(x): return "(" + x + ")"
-        
-        if values:
-            _keys = SQLQuery.join(values.keys(), ', ')
-            _values = SQLQuery.join([sqlparam(v) for v in values.values()], ', ')
-            sql_query = "INSERT INTO %s " % tablename + q(_keys) + ' VALUES ' + q(_values)
-        else:
-            sql_query = SQLQuery("INSERT INTO %s DEFAULT VALUES" % tablename)
-
-        if _test: return sql_query
-        
-        db_cursor = self._db_cursor()
-        if seqname is not False: 
-            sql_query = self._process_insert_query(sql_query, tablename, seqname)
-
-        if isinstance(sql_query, tuple):
-            # for some databases, a separate query has to be made to find 
-            # the id of the inserted row.
-            q1, q2 = sql_query
-            self._db_execute(db_cursor, q1)
-            self._db_execute(db_cursor, q2)
-        else:
-            self._db_execute(db_cursor, sql_query)
-
-        try: 
-            out = db_cursor.fetchone()[0]
-        except Exception: 
-            out = None
-        
-        if not self.ctx.transactions: 
-            self.ctx.commit()
-        return out
-        
-    def multiple_insert(self, tablename, values, seqname=None, _test=False):
-        """
-        Inserts multiple rows into `tablename`. The `values` must be a list of dictioanries, 
-        one for each row to be inserted, each with the same set of keys.
-        Returns the list of ids of the inserted rows.        
-        Set `seqname` to the ID if it's not the default, or to `False`
-        if there isn't one.
-        
-            >>> db = DB(None, {})
-            >>> db.supports_multiple_insert = True
-            >>> values = [{"name": "foo", "email": "foo@example.com"}, {"name": "bar", "email": "bar@example.com"}]
-            >>> db.multiple_insert('person', values=values, _test=True)
-            <sql: "INSERT INTO person (name, email) VALUES ('foo', 'foo@example.com'), ('bar', 'bar@example.com')">
-        """        
-        if not values:
-            return []
-            
-        if not self.supports_multiple_insert:
-            out = [self.insert(tablename, seqname=seqname, _test=_test, **v) for v in values]
-            if seqname is False:
-                return None
-            else:
-                return out
-                
-        keys = values[0].keys()
-        #@@ make sure all keys are valid
-
-        # make sure all rows have same keys.
-        for v in values:
-            if v.keys() != keys:
-                raise ValueError, 'Bad data'
-
-        sql_query = SQLQuery('INSERT INTO %s (%s) VALUES ' % (tablename, ', '.join(keys))) 
-
-        data = []
-        for row in values:
-            d = SQLQuery.join([SQLParam(row[k]) for k in keys], ', ')
-            data.append('(' + d + ')')
-        sql_query += SQLQuery.join(data, ', ')
-
-        if _test: return sql_query
-
-        db_cursor = self._db_cursor()
-        if seqname is not False: 
-            sql_query = self._process_insert_query(sql_query, tablename, seqname)
-
-        if isinstance(sql_query, tuple):
-            # for some databases, a separate query has to be made to find 
-            # the id of the inserted row.
-            q1, q2 = sql_query
-            self._db_execute(db_cursor, q1)
-            self._db_execute(db_cursor, q2)
-        else:
-            self._db_execute(db_cursor, sql_query)
-
-        try: 
-            out = db_cursor.fetchone()[0]
-            out = range(out-len(values)+1, out+1)        
-        except Exception: 
-            out = None
-
-        if not self.ctx.transactions: 
-            self.ctx.commit()
-        return out
-
-    
-    def update(self, tables, where, vars=None, _test=False, **values): 
-        """
-        Update `tables` with clause `where` (interpolated using `vars`)
-        and setting `values`.
-
-            >>> db = DB(None, {})
-            >>> name = 'Joseph'
-            >>> q = db.update('foo', where='name = $name', name='bob', age=2,
-            ...     created=SQLLiteral('NOW()'), vars=locals(), _test=True)
-            >>> q
-            <sql: "UPDATE foo SET age = 2, name = 'bob', created = NOW() WHERE name = 'Joseph'">
-            >>> q.query()
-            'UPDATE foo SET age = %s, name = %s, created = NOW() WHERE name = %s'
-            >>> q.values()
-            [2, 'bob', 'Joseph']
-        """
-        if vars is None: vars = {}
-        where = self._where(where, vars)
-
-        query = (
-          "UPDATE " + sqllist(tables) + 
-          " SET " + sqlwhere(values, ', ') + 
-          " WHERE " + where)
-
-        if _test: return query
-        
-        db_cursor = self._db_cursor()
-        self._db_execute(db_cursor, query)
-        if not self.ctx.transactions: 
-            self.ctx.commit()
-        return db_cursor.rowcount
-    
-    def delete(self, table, where, using=None, vars=None, _test=False): 
-        """
-        Deletes from `table` with clauses `where` and `using`.
-
-            >>> db = DB(None, {})
-            >>> name = 'Joe'
-            >>> db.delete('foo', where='name = $name', vars=locals(), _test=True)
-            <sql: "DELETE FROM foo WHERE name = 'Joe'">
-        """
-        if vars is None: vars = {}
-        where = self._where(where, vars)
-
-        q = 'DELETE FROM ' + table
-        if where: q += ' WHERE ' + where
-        if using: q += ' USING ' + sqllist(using)
-
-        if _test: return q
-
-        db_cursor = self._db_cursor()
-        self._db_execute(db_cursor, q)
-        if not self.ctx.transactions: 
-            self.ctx.commit()
-        return db_cursor.rowcount
-
-    def _process_insert_query(self, query, tablename, seqname):
-        return query
-
-    def transaction(self): 
-        """Start a transaction."""
-        return Transaction(self.ctx)
-    
-class PostgresDB(DB): 
-    """Postgres driver."""
-    def __init__(self, **keywords):
-        if 'pw' in keywords:
-            keywords['password'] = keywords['pw']
-            del keywords['pw']
-            
-        db_module = import_driver(["psycopg2", "psycopg", "pgdb"], preferred=keywords.pop('driver', None))
-        if db_module.__name__ == "psycopg2":
-            import psycopg2.extensions
-            psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
-
-        keywords['database'] = keywords.pop('db')
-        self.dbname = "postgres"
-        self.paramstyle = db_module.paramstyle
-        DB.__init__(self, db_module, keywords)
-        self.supports_multiple_insert = True
-        
-    def _process_insert_query(self, query, tablename, seqname):
-        if seqname is None: 
-            seqname = tablename + "_id_seq"
-        return query + "; SELECT currval('%s')" % seqname
-
-    def _connect(self, keywords):
-        conn = DB._connect(self, keywords)
-        conn.set_client_encoding('UTF8')
-        return conn
-        
-    def _connect_with_pooling(self, keywords):
-        conn = DB._connect_with_pooling(self, keywords)
-        conn._con._con.set_client_encoding('UTF8')
-        return conn
-
-class MySQLDB(DB): 
-    def __init__(self, **keywords):
-        import MySQLdb as db
-        if 'pw' in keywords:
-            keywords['passwd'] = keywords['pw']
-            del keywords['pw']
-
-        if 'charset' not in keywords:
-            keywords['charset'] = 'utf8'
-        elif keywords['charset'] is None:
-            del keywords['charset']
-
-        self.paramstyle = db.paramstyle = 'pyformat' # it's both, like psycopg
-        self.dbname = "mysql"
-        DB.__init__(self, db, keywords)
-        self.supports_multiple_insert = True
-        
-    def _process_insert_query(self, query, tablename, seqname):
-        return query, SQLQuery('SELECT last_insert_id();')
-
-def import_driver(drivers, preferred=None):
-    """Import the first available driver or preferred driver.
-    """
-    if preferred:
-        drivers = [preferred]
-
-    for d in drivers:
-        try:
-            return __import__(d, None, None, ['x'])
-        except ImportError:
-            pass
-    raise ImportError("Unable to import " + " or ".join(drivers))
-
-class SqliteDB(DB): 
-    def __init__(self, **keywords):
-        db = import_driver(["sqlite3", "pysqlite2.dbapi2", "sqlite"], preferred=keywords.pop('driver', None))
-
-        if db.__name__ in ["sqlite3", "pysqlite2.dbapi2"]:
-            db.paramstyle = 'qmark'
-
-        self.paramstyle = db.paramstyle
-        keywords['database'] = keywords.pop('db')
-        self.dbname = "sqlite"        
-        DB.__init__(self, db, keywords)
-
-    def _process_insert_query(self, query, tablename, seqname):
-        return query, SQLQuery('SELECT last_insert_rowid();')
-    
-    def query(self, *a, **kw):
-        out = DB.query(self, *a, **kw)
-        if isinstance(out, iterbetter):
-            # rowcount is not provided by sqlite
-            del out.__len__
-        return out
-
-class FirebirdDB(DB):
-    """Firebird Database.
-    """
-    def __init__(self, **keywords):
-        try:
-            import kinterbasdb as db
-        except Exception:
-            db = None
-            pass
-        if 'pw' in keywords:
-            keywords['passwd'] = keywords['pw']
-            del keywords['pw']
-        keywords['database'] = keywords['db']
-        del keywords['db']
-        DB.__init__(self, db, keywords)
-        
-    def delete(self, table, where=None, using=None, vars=None, _test=False):
-        # firebird doesn't support using clause
-        using=None
-        return DB.delete(self, table, where, using, vars, _test)
-
-    def sql_clauses(self, what, tables, where, group, order, limit, offset):
-        return (
-            ('SELECT', ''),
-            ('FIRST', limit),
-            ('SKIP', offset),
-            ('', what),
-            ('FROM', sqllist(tables)),
-            ('WHERE', where),
-            ('GROUP BY', group),
-            ('ORDER BY', order)
-        )
-
-class MSSQLDB(DB):
-    def __init__(self, **keywords):
-        import pymssql as db    
-        if 'pw' in keywords:
-            keywords['password'] = keywords.pop('pw')
-        keywords['database'] = keywords.pop('db')
-        self.dbname = "mssql"
-        DB.__init__(self, db, keywords)
-
-    def sql_clauses(self, what, tables, where, group, order, limit, offset): 
-        return (
-            ('SELECT', what),
-            ('TOP', limit),
-            ('FROM', sqllist(tables)),
-            ('WHERE', where),
-            ('GROUP BY', group),
-            ('ORDER BY', order),
-            ('OFFSET', offset))
-            
-    def _test(self):
-        """Test LIMIT.
-
-            Fake presence of pymssql module for running tests.
-            >>> import sys
-            >>> sys.modules['pymssql'] = sys.modules['sys']
-            
-            MSSQL has TOP clause instead of LIMIT clause.
-            >>> db = MSSQLDB(db='test', user='joe', pw='secret')
-            >>> db.select('foo', limit=4, _test=True)
-            <sql: 'SELECT * TOP 4 FROM foo'>
-        """
-        pass
-
-class OracleDB(DB): 
-    def __init__(self, **keywords): 
-        import cx_Oracle as db 
-        if 'pw' in keywords: 
-            keywords['password'] = keywords.pop('pw') 
-
-        #@@ TODO: use db.makedsn if host, port is specified 
-        keywords['dsn'] = keywords.pop('db') 
-        self.dbname = 'oracle' 
-        db.paramstyle = 'numeric' 
-        self.paramstyle = db.paramstyle
-
-        # oracle doesn't support pooling 
-        keywords.pop('pooling', None) 
-        DB.__init__(self, db, keywords) 
-
-    def _process_insert_query(self, query, tablename, seqname): 
-        if seqname is None: 
-            # It is not possible to get seq name from table name in Oracle
-            return query
-        else:
-            return query + "; SELECT %s.currval FROM dual" % seqname 
-
-_databases = {}
-def database(dburl=None, **params):
-    """Creates appropriate database using params.
-    
-    Pooling will be enabled if DBUtils module is available. 
-    Pooling can be disabled by passing pooling=False in params.
-    """
-    dbn = params.pop('dbn')
-    if dbn in _databases:
-        return _databases[dbn](**params)
-    else:
-        raise UnknownDB, dbn
-
-def register_database(name, clazz):
-    """
-    Register a database.
-
-        >>> class LegacyDB(DB): 
-        ...     def __init__(self, **params): 
-        ...        pass 
-        ...
-        >>> register_database('legacy', LegacyDB)
-        >>> db = database(dbn='legacy', db='test', user='joe', passwd='secret') 
-    """
-    _databases[name] = clazz
-
-register_database('mysql', MySQLDB)
-register_database('postgres', PostgresDB)
-register_database('sqlite', SqliteDB)
-register_database('firebird', FirebirdDB)
-register_database('mssql', MSSQLDB)
-register_database('oracle', OracleDB)
-
-def _interpolate(format): 
-    """
-    Takes a format string and returns a list of 2-tuples of the form
-    (boolean, string) where boolean says whether string should be evaled
-    or not.
-
-    from <http://lfw.org/python/Itpl.py> (public domain, Ka-Ping Yee)
-    """
-    from tokenize import tokenprog
-
-    def matchorfail(text, pos):
-        match = tokenprog.match(text, pos)
-        if match is None:
-            raise _ItplError(text, pos)
-        return match, match.end()
-
-    namechars = "abcdefghijklmnopqrstuvwxyz" \
-        "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
-    chunks = []
-    pos = 0
-
-    while 1:
-        dollar = format.find("$", pos)
-        if dollar < 0: 
-            break
-        nextchar = format[dollar + 1]
-
-        if nextchar == "{":
-            chunks.append((0, format[pos:dollar]))
-            pos, level = dollar + 2, 1
-            while level:
-                match, pos = matchorfail(format, pos)
-                tstart, tend = match.regs[3]
-                token = format[tstart:tend]
-                if token == "{": 
-                    level = level + 1
-                elif token == "}":  
-                    level = level - 1
-            chunks.append((1, format[dollar + 2:pos - 1]))
-
-        elif nextchar in namechars:
-            chunks.append((0, format[pos:dollar]))
-            match, pos = matchorfail(format, dollar + 1)
-            while pos < len(format):
-                if format[pos] == "." and \
-                    pos + 1 < len(format) and format[pos + 1] in namechars:
-                    match, pos = matchorfail(format, pos + 1)
-                elif format[pos] in "([":
-                    pos, level = pos + 1, 1
-                    while level:
-                        match, pos = matchorfail(format, pos)
-                        tstart, tend = match.regs[3]
-                        token = format[tstart:tend]
-                        if token[0] in "([": 
-                            level = level + 1
-                        elif token[0] in ")]":  
-                            level = level - 1
-                else: 
-                    break
-            chunks.append((1, format[dollar + 1:pos]))
-        else:
-            chunks.append((0, format[pos:dollar + 1]))
-            pos = dollar + 1 + (nextchar == "$")
-
-    if pos < len(format): 
-        chunks.append((0, format[pos:]))
-    return chunks
-
-if __name__ == "__main__":
-    import doctest
-    doctest.testmod()
--- a/bundled/webpy/web/debugerror.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,356 +0,0 @@
-"""
-pretty debug errors
-(part of web.py)
-
-portions adapted from Django <djangoproject.com> 
-Copyright (c) 2005, the Lawrence Journal-World
-Used under the modified BSD license:
-http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
-"""
-
-__all__ = ["debugerror", "djangoerror", "emailerrors"]
-
-import sys, urlparse, pprint, traceback
-from net import websafe
-from template import Template
-from utils import sendmail
-import webapi as web
-
-import os, os.path
-whereami = os.path.join(os.getcwd(), __file__)
-whereami = os.path.sep.join(whereami.split(os.path.sep)[:-1])
-djangoerror_t = """\
-$def with (exception_type, exception_value, frames)
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
-<html lang="en">
-<head>
-  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
-  <meta name="robots" content="NONE,NOARCHIVE" />
-  <title>$exception_type at $ctx.path</title>
-  <style type="text/css">
-    html * { padding:0; margin:0; }
-    body * { padding:10px 20px; }
-    body * * { padding:0; }
-    body { font:small sans-serif; }
-    body>div { border-bottom:1px solid #ddd; }
-    h1 { font-weight:normal; }
-    h2 { margin-bottom:.8em; }
-    h2 span { font-size:80%; color:#666; font-weight:normal; }
-    h3 { margin:1em 0 .5em 0; }
-    h4 { margin:0 0 .5em 0; font-weight: normal; }
-    table { 
-        border:1px solid #ccc; border-collapse: collapse; background:white; }
-    tbody td, tbody th { vertical-align:top; padding:2px 3px; }
-    thead th { 
-        padding:1px 6px 1px 3px; background:#fefefe; text-align:left; 
-        font-weight:normal; font-size:11px; border:1px solid #ddd; }
-    tbody th { text-align:right; color:#666; padding-right:.5em; }
-    table.vars { margin:5px 0 2px 40px; }
-    table.vars td, table.req td { font-family:monospace; }
-    table td.code { width:100%;}
-    table td.code div { overflow:hidden; }
-    table.source th { color:#666; }
-    table.source td { 
-        font-family:monospace; white-space:pre; border-bottom:1px solid #eee; }
-    ul.traceback { list-style-type:none; }
-    ul.traceback li.frame { margin-bottom:1em; }
-    div.context { margin: 10px 0; }
-    div.context ol { 
-        padding-left:30px; margin:0 10px; list-style-position: inside; }
-    div.context ol li { 
-        font-family:monospace; white-space:pre; color:#666; cursor:pointer; }
-    div.context ol.context-line li { color:black; background-color:#ccc; }
-    div.context ol.context-line li span { float: right; }
-    div.commands { margin-left: 40px; }
-    div.commands a { color:black; text-decoration:none; }
-    #summary { background: #ffc; }
-    #summary h2 { font-weight: normal; color: #666; }
-    #explanation { background:#eee; }
-    #template, #template-not-exist { background:#f6f6f6; }
-    #template-not-exist ul { margin: 0 0 0 20px; }
-    #traceback { background:#eee; }
-    #requestinfo { background:#f6f6f6; padding-left:120px; }
-    #summary table { border:none; background:transparent; }
-    #requestinfo h2, #requestinfo h3 { position:relative; margin-left:-100px; }
-    #requestinfo h3 { margin-bottom:-1em; }
-    .error { background: #ffc; }
-    .specific { color:#cc3300; font-weight:bold; }
-  </style>
-  <script type="text/javascript">
-  //<!--
-    function getElementsByClassName(oElm, strTagName, strClassName){
-        // Written by Jonathan Snook, http://www.snook.ca/jon; 
-        // Add-ons by Robert Nyman, http://www.robertnyman.com
-        var arrElements = (strTagName == "*" && document.all)? document.all :
-        oElm.getElementsByTagName(strTagName);
-        var arrReturnElements = new Array();
-        strClassName = strClassName.replace(/\-/g, "\\-");
-        var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$$)");
-        var oElement;
-        for(var i=0; i<arrElements.length; i++){
-            oElement = arrElements[i];
-            if(oRegExp.test(oElement.className)){
-                arrReturnElements.push(oElement);
-            }
-        }
-        return (arrReturnElements)
-    }
-    function hideAll(elems) {
-      for (var e = 0; e < elems.length; e++) {
-        elems[e].style.display = 'none';
-      }
-    }
-    window.onload = function() {
-      hideAll(getElementsByClassName(document, 'table', 'vars'));
-      hideAll(getElementsByClassName(document, 'ol', 'pre-context'));
-      hideAll(getElementsByClassName(document, 'ol', 'post-context'));
-    }
-    function toggle() {
-      for (var i = 0; i < arguments.length; i++) {
-        var e = document.getElementById(arguments[i]);
-        if (e) {
-          e.style.display = e.style.display == 'none' ? 'block' : 'none';
-        }
-      }
-      return false;
-    }
-    function varToggle(link, id) {
-      toggle('v' + id);
-      var s = link.getElementsByTagName('span')[0];
-      var uarr = String.fromCharCode(0x25b6);
-      var darr = String.fromCharCode(0x25bc);
-      s.innerHTML = s.innerHTML == uarr ? darr : uarr;
-      return false;
-    }
-    //-->
-  </script>
-</head>
-<body>
-
-$def dicttable (d, kls='req', id=None):
-    $ items = d and d.items() or []
-    $items.sort()
-    $:dicttable_items(items, kls, id)
-        
-$def dicttable_items(items, kls='req', id=None):
-    $if items:
-        <table class="$kls"
-        $if id: id="$id"
-        ><thead><tr><th>Variable</th><th>Value</th></tr></thead>
-        <tbody>
-        $for k, v in items:
-            <tr><td>$k</td><td class="code"><div>$prettify(v)</div></td></tr>
-        </tbody>
-        </table>
-    $else:
-        <p>No data.</p>
-
-<div id="summary">
-  <h1>$exception_type at $ctx.path</h1>
-  <h2>$exception_value</h2>
-  <table><tr>
-    <th>Python</th>
-    <td>$frames[0].filename in $frames[0].function, line $frames[0].lineno</td>
-  </tr><tr>
-    <th>Web</th>
-    <td>$ctx.method $ctx.home$ctx.path</td>
-  </tr></table>
-</div>
-<div id="traceback">
-<h2>Traceback <span>(innermost first)</span></h2>
-<ul class="traceback">
-$for frame in frames:
-    <li class="frame">
-    <code>$frame.filename</code> in <code>$frame.function</code>
-    $if frame.context_line:
-        <div class="context" id="c$frame.id">
-        $if frame.pre_context:
-            <ol start="$frame.pre_context_lineno" class="pre-context" id="pre$frame.id">
-            $for line in frame.pre_context:
-                <li onclick="toggle('pre$frame.id', 'post$frame.id')">$line</li>
-            </ol>
-            <ol start="$frame.lineno" class="context-line"><li onclick="toggle('pre$frame.id', 'post$frame.id')">$frame.context_line <span>...</span></li></ol>
-        $if frame.post_context:
-            <ol start='${frame.lineno + 1}' class="post-context" id="post$frame.id">
-            $for line in frame.post_context:
-                <li onclick="toggle('pre$frame.id', 'post$frame.id')">$line</li>
-            </ol>
-      </div>
-    
-    $if frame.vars:
-        <div class="commands">
-        <a href='#' onclick="return varToggle(this, '$frame.id')"><span>&#x25b6;</span> Local vars</a>
-        $# $inspect.formatargvalues(*inspect.getargvalues(frame['tb'].tb_frame))
-        </div>
-        $:dicttable(frame.vars, kls='vars', id=('v' + str(frame.id)))
-      </li>
-  </ul>
-</div>
-
-<div id="requestinfo">
-$if ctx.output or ctx.headers:
-    <h2>Response so far</h2>
-    <h3>HEADERS</h3>
-    $:dicttable_items(ctx.headers)
-
-    <h3>BODY</h3>
-    <p class="req" style="padding-bottom: 2em"><code>
-    $ctx.output
-    </code></p>
-  
-<h2>Request information</h2>
-
-<h3>INPUT</h3>
-$:dicttable(web.input())
-
-<h3 id="cookie-info">COOKIES</h3>
-$:dicttable(web.cookies())
-
-<h3 id="meta-info">META</h3>
-$ newctx = [(k, v) for (k, v) in ctx.iteritems() if not k.startswith('_') and not isinstance(v, dict)]
-$:dicttable(dict(newctx))
-
-<h3 id="meta-info">ENVIRONMENT</h3>
-$:dicttable(ctx.env)
-</div>
-
-<div id="explanation">
-  <p>
-    You're seeing this error because you have <code>web.config.debug</code>
-    set to <code>True</code>. Set that to <code>False</code> if you don't to see this.
-  </p>
-</div>
-
-</body>
-</html>
-"""
-
-djangoerror_r = None
-
-def djangoerror():
-    def _get_lines_from_file(filename, lineno, context_lines):
-        """
-        Returns context_lines before and after lineno from file.
-        Returns (pre_context_lineno, pre_context, context_line, post_context).
-        """
-        try:
-            source = open(filename).readlines()
-            lower_bound = max(0, lineno - context_lines)
-            upper_bound = lineno + context_lines
-
-            pre_context = \
-                [line.strip('\n') for line in source[lower_bound:lineno]]
-            context_line = source[lineno].strip('\n')
-            post_context = \
-                [line.strip('\n') for line in source[lineno + 1:upper_bound]]
-
-            return lower_bound, pre_context, context_line, post_context
-        except (OSError, IOError):
-            return None, [], None, []    
-    
-    exception_type, exception_value, tback = sys.exc_info()
-    frames = []
-    while tback is not None:
-        filename = tback.tb_frame.f_code.co_filename
-        function = tback.tb_frame.f_code.co_name
-        lineno = tback.tb_lineno - 1
-        pre_context_lineno, pre_context, context_line, post_context = \
-            _get_lines_from_file(filename, lineno, 7)
-        frames.append(web.storage({
-            'tback': tback,
-            'filename': filename,
-            'function': function,
-            'lineno': lineno,
-            'vars': tback.tb_frame.f_locals,
-            'id': id(tback),
-            'pre_context': pre_context,
-            'context_line': context_line,
-            'post_context': post_context,
-            'pre_context_lineno': pre_context_lineno,
-        }))
-        tback = tback.tb_next
-    frames.reverse()
-    urljoin = urlparse.urljoin
-    def prettify(x):
-        try: 
-            out = pprint.pformat(x)
-        except Exception, e: 
-            out = '[could not display: <' + e.__class__.__name__ + \
-                  ': '+str(e)+'>]'
-        return out
-        
-    global djangoerror_r
-    if djangoerror_r is None:
-        djangoerror_r = Template(djangoerror_t, filename=__file__, filter=websafe)
-        
-    t = djangoerror_r
-    globals = {'ctx': web.ctx, 'web':web, 'dict':dict, 'str':str, 'prettify': prettify}
-    t.t.func_globals.update(globals)
-    return t(exception_type, exception_value, frames)
-
-def debugerror():
-    """
-    A replacement for `internalerror` that presents a nice page with lots
-    of debug information for the programmer.
-
-    (Based on the beautiful 500 page from [Django](http://djangoproject.com/), 
-    designed by [Wilson Miner](http://wilsonminer.com/).)
-    """
-    return web._InternalError(djangoerror())
-
-def emailerrors(to_address, olderror, from_address=None):
-    """
-    Wraps the old `internalerror` handler (pass as `olderror`) to 
-    additionally email all errors to `to_address`, to aid in
-    debugging production websites.
-    
-    Emails contain a normal text traceback as well as an
-    attachment containing the nice `debugerror` page.
-    """
-    from_address = from_address or to_address
-
-    def emailerrors_internal():
-        error = olderror()
-        tb = sys.exc_info()
-        error_name = tb[0]
-        error_value = tb[1]
-        tb_txt = ''.join(traceback.format_exception(*tb))
-        path = web.ctx.path
-        request = web.ctx.method + ' ' + web.ctx.home + web.ctx.fullpath
-        text = ("""\
-------here----
-Content-Type: text/plain
-Content-Disposition: inline
-
-%(request)s
-
-%(tb_txt)s
-
-------here----
-Content-Type: text/html; name="bug.html"
-Content-Disposition: attachment; filename="bug.html"
-
-""" % locals()) + str(djangoerror())
-        sendmail(
-          "your buggy site <%s>" % from_address,
-          "the bugfixer <%s>" % to_address,
-          "bug: %(error_name)s: %(error_value)s (%(path)s)" % locals(),
-          text, 
-          headers={'Content-Type': 'multipart/mixed; boundary="----here----"'})
-        return error
-    
-    return emailerrors_internal
-
-if __name__ == "__main__":
-    urls = (
-        '/', 'index'
-    )
-    from application import application
-    app = application(urls, globals())
-    app.internalerror = debugerror
-    
-    class index:
-        def GET(self):
-            thisdoesnotexist
-
-    app.run()
--- a/bundled/webpy/web/form.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,264 +0,0 @@
-"""
-HTML forms
-(part of web.py)
-"""
-
-import copy, re
-import webapi as web
-import utils, net
-
-def attrget(obj, attr, value=None):
-    if hasattr(obj, 'has_key') and obj.has_key(attr): return obj[attr]
-    if hasattr(obj, attr): return getattr(obj, attr)
-    return value
-
-class Form:
-    r"""
-    HTML form.
-    
-        >>> f = Form(Textbox("x"))
-        >>> f.render()
-        '<table>\n    <tr><th><label for="x">x</label></th><td><input type="text" name="x" id="x" /></td></tr>\n</table>'
-    """
-    def __init__(self, *inputs, **kw):
-        self.inputs = inputs
-        self.valid = True
-        self.note = None
-        self.validators = kw.pop('validators', [])
-
-    def __call__(self, x=None):
-        o = copy.deepcopy(self)
-        if x: o.validates(x)
-        return o
-    
-    def render(self):
-        out = ''
-        out += self.rendernote(self.note)
-        out += '<table>\n'
-        for i in self.inputs:
-            out += '    <tr><th><label for="%s">%s</label></th>' % (i.id, net.websafe(i.description))
-            out += "<td>"+i.pre+i.render()+i.post+"</td></tr>\n"
-        out += "</table>"
-        return out
-        
-    def render_css(self): 
-        out = [] 
-        out.append(self.rendernote(self.note)) 
-        for i in self.inputs: 
-            out.append('<label for="%s">%s</label>' % (i.id, net.websafe(i.description))) 
-            out.append(i.pre) 
-            out.append(i.render()) 
-            out.append(i.post) 
-            out.append('\n') 
-        return ''.join(out) 
-        
-    def rendernote(self, note):
-        if note: return '<strong class="wrong">%s</strong>' % net.websafe(note)
-        else: return ""
-    
-    def validates(self, source=None, _validate=True, **kw):
-        source = source or kw or web.input()
-        out = True
-        for i in self.inputs:
-            v = attrget(source, i.name)
-            if _validate:
-                out = i.validate(v) and out
-            else:
-                i.value = v
-        if _validate:
-            out = out and self._validate(source)
-            self.valid = out
-        return out
-
-    def _validate(self, value):
-        self.value = value
-        for v in self.validators:
-            if not v.valid(value):
-                self.note = v.msg
-                return False
-        return True
-
-    def fill(self, source=None, **kw):
-        return self.validates(source, _validate=False, **kw)
-    
-    def __getitem__(self, i):
-        for x in self.inputs:
-            if x.name == i: return x
-        raise KeyError, i
-
-    def __getattr__(self, name):
-        # don't interfere with deepcopy
-        inputs = self.__dict__.get('inputs') or []
-        for x in inputs:
-            if x.name == name: return x
-        raise AttributeError, name
-    
-    def get(self, i, default=None):
-        try:
-            return self[i]
-        except KeyError:
-            return default
-            
-    def _get_d(self): #@@ should really be form.attr, no?
-        return utils.storage([(i.name, i.value) for i in self.inputs])
-    d = property(_get_d)
-
-class Input(object):
-    def __init__(self, name, *validators, **attrs):
-        self.description = attrs.pop('description', name)
-        self.value = attrs.pop('value', None)
-        self.pre = attrs.pop('pre', "")
-        self.post = attrs.pop('post', "")
-        self.id = attrs.setdefault('id', name)
-        if 'class_' in attrs:
-            attrs['class'] = attrs['class_']
-            del attrs['class_']
-        self.name, self.validators, self.attrs, self.note = name, validators, attrs, None
-
-    def validate(self, value):
-        self.value = value
-        for v in self.validators:
-            if not v.valid(value):
-                self.note = v.msg
-                return False
-        return True
-
-    def render(self): raise NotImplementedError
-
-    def rendernote(self, note):
-        if note: return '<strong class="wrong">%s</strong>' % net.websafe(note)
-        else: return ""
-        
-    def addatts(self):
-        str = ""
-        for (n, v) in self.attrs.items():
-            str += ' %s="%s"' % (n, net.websafe(v))
-        return str
-    
-#@@ quoting
-
-class Textbox(Input):
-    def render(self, shownote=True):
-        x = '<input type="text" name="%s"' % net.websafe(self.name)
-        if self.value: x += ' value="%s"' % net.websafe(self.value)
-        x += self.addatts()
-        x += ' />'
-        if shownote:
-            x += self.rendernote(self.note)
-        return x
-
-class Password(Input):
-    def render(self):
-        x = '<input type="password" name="%s"' % net.websafe(self.name)
-        if self.value: x += ' value="%s"' % net.websafe(self.value)
-        x += self.addatts()
-        x += ' />'
-        x += self.rendernote(self.note)
-        return x
-
-class Textarea(Input):
-    def render(self):
-        x = '<textarea name="%s"' % net.websafe(self.name)
-        x += self.addatts()
-        x += '>'
-        if self.value is not None: x += net.websafe(self.value)
-        x += '</textarea>'
-        x += self.rendernote(self.note)
-        return x
-
-class Dropdown(Input):
-    def __init__(self, name, args, *validators, **attrs):
-        self.args = args
-        super(Dropdown, self).__init__(name, *validators, **attrs)
-
-    def render(self):
-        x = '<select name="%s"%s>\n' % (net.websafe(self.name), self.addatts())
-        for arg in self.args:
-            if isinstance(arg, (tuple, list)):
-                value, desc= arg
-            else:
-                value, desc = arg, arg 
-
-            if self.value == value: select_p = ' selected="selected"'
-            else: select_p = ''
-            x += '  <option %s value="%s">%s</option>\n' % (select_p, net.websafe(value), net.websafe(desc))
-        x += '</select>\n'
-        x += self.rendernote(self.note)
-        return x
-
-class Radio(Input):
-    def __init__(self, name, args, *validators, **attrs):
-        self.args = args
-        super(Radio, self).__init__(name, *validators, **attrs)
-
-    def render(self):
-        x = '<span>'
-        for arg in self.args:
-            if self.value == arg: select_p = ' checked="checked"'
-            else: select_p = ''
-            x += '<input type="radio" name="%s" value="%s"%s%s /> %s ' % (net.websafe(self.name), net.websafe(arg), select_p, self.addatts(), net.websafe(arg))
-            x += '</span>'
-            x += self.rendernote(self.note)    
-        return x
-
-class Checkbox(Input):
-    def render(self):
-        x = '<input name="%s" type="checkbox"' % net.websafe(self.name)
-        if self.value: x += ' checked="checked"'
-        x += self.addatts()
-        x += ' />'
-        x += self.rendernote(self.note)
-        return x
-
-class Button(Input):
-    def __init__(self, name, *validators, **attrs):
-        super(Button, self).__init__(name, *validators, **attrs)
-        self.description = ""
-
-    def render(self):
-        safename = net.websafe(self.name)
-        x = '<button name="%s"%s>%s</button>' % (safename, self.addatts(), safename)
-        x += self.rendernote(self.note)
-        return x
-
-class Hidden(Input):
-    def __init__(self, name, *validators, **attrs):
-        super(Hidden, self).__init__(name, *validators, **attrs)
-        # it doesnt make sence for a hidden field to have description
-        self.description = ""
-
-    def render(self):
-        x = '<input type="hidden" name="%s"' % net.websafe(self.name)
-        if self.value: x += ' value="%s"' % net.websafe(self.value)
-        x += self.addatts()
-        x += ' />'
-        return x
-
-class File(Input):
-    def render(self):
-        x = '<input type="file" name="%s"' % net.websafe(self.name)
-        x += self.addatts()
-        x += ' />'
-        x += self.rendernote(self.note)
-        return x
-    
-class Validator:
-    def __deepcopy__(self, memo): return copy.copy(self)
-    def __init__(self, msg, test, jstest=None): utils.autoassign(self, locals())
-    def valid(self, value): 
-        try: return self.test(value)
-        except: return False
-
-notnull = Validator("Required", bool)
-
-class regexp(Validator):
-    def __init__(self, rexp, msg):
-        self.rexp = re.compile(rexp)
-        self.msg = msg
-    
-    def valid(self, value):
-        return bool(self.rexp.match(value))
-
-if __name__ == "__main__":
-    import doctest
-    doctest.testmod()
--- a/bundled/webpy/web/http.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,163 +0,0 @@
-"""
-HTTP Utilities
-(from web.py)
-"""
-
-__all__ = [
-  "expires", "lastmodified", 
-  "prefixurl", "modified", 
-  "write",
-  "changequery", "url",
-  "profiler",
-]
-
-import sys, os, threading, urllib, urlparse
-try: import datetime
-except ImportError: pass
-import net, utils, webapi as web
-
-def prefixurl(base=''):
-    """
-    Sorry, this function is really difficult to explain.
-    Maybe some other time.
-    """
-    url = web.ctx.path.lstrip('/')
-    for i in xrange(url.count('/')): 
-        base += '../'
-    if not base: 
-        base = './'
-    return base
-
-def expires(delta):
-    """
-    Outputs an `Expires` header for `delta` from now. 
-    `delta` is a `timedelta` object or a number of seconds.
-    """
-    if isinstance(delta, (int, long)):
-        delta = datetime.timedelta(seconds=delta)
-    date_obj = datetime.datetime.utcnow() + delta
-    web.header('Expires', net.httpdate(date_obj))
-
-def lastmodified(date_obj):
-    """Outputs a `Last-Modified` header for `datetime`."""
-    web.header('Last-Modified', net.httpdate(date_obj))
-
-def modified(date=None, etag=None):
-    """
-    Checks to see if the page has been modified since the version in the
-    requester's cache.
-    
-    When you publish pages, you can include `Last-Modified` and `ETag`
-    with the date the page was last modified and an opaque token for
-    the particular version, respectively. When readers reload the page, 
-    the browser sends along the modification date and etag value for
-    the version it has in its cache. If the page hasn't changed, 
-    the server can just return `304 Not Modified` and not have to 
-    send the whole page again.
-    
-    This function takes the last-modified date `date` and the ETag `etag`
-    and checks the headers to see if they match. If they do, it returns 
-    `True` and sets the response status to `304 Not Modified`. It also
-    sets `Last-Modified and `ETag` output headers.
-    """
-    try:
-        from __builtin__ import set
-    except ImportError:
-        # for python 2.3
-        from sets import Set as set
-
-    n = set([x.strip('" ') for x in web.ctx.env.get('HTTP_IF_NONE_MATCH', '').split(',')])
-    m = net.parsehttpdate(web.ctx.env.get('HTTP_IF_MODIFIED_SINCE', '').split(';')[0])
-    validate = False
-    if etag:
-        if '*' in n or etag in n:
-            validate = True
-    if date and m:
-        # we subtract a second because 
-        # HTTP dates don't have sub-second precision
-        if date-datetime.timedelta(seconds=1) <= m:
-            validate = True
-    
-    if validate: web.ctx.status = '304 Not Modified'
-    if date: lastmodified(date)
-    if etag: web.header('ETag', '"' + etag + '"')
-    return not validate
-
-def write(cgi_response):
-    """
-    Converts a standard CGI-style string response into `header` and 
-    `output` calls.
-    """
-    cgi_response = str(cgi_response)
-    cgi_response.replace('\r\n', '\n')
-    head, body = cgi_response.split('\n\n', 1)
-    lines = head.split('\n')
-
-    for line in lines:
-        if line.isspace(): 
-            continue
-        hdr, value = line.split(":", 1)
-        value = value.strip()
-        if hdr.lower() == "status": 
-            web.ctx.status = value
-        else: 
-            web.header(hdr, value)
-
-    web.output(body)
-
-def urlencode(query):
-    """
-    Same as urllib.urlencode, but supports unicode strings.
-    
-        >>> urlencode({'text':'foo bar'})
-        'text=foo+bar'
-    """
-    query = dict([(k, utils.utf8(v)) for k, v in query.items()])
-    return urllib.urlencode(query)
-
-def changequery(query=None, **kw):
-    """
-    Imagine you're at `/foo?a=1&b=2`. Then `changequery(a=3)` will return
-    `/foo?a=3&b=2` -- the same URL but with the arguments you requested
-    changed.
-    """
-    if query is None:
-        query = web.input(_method='get')
-    for k, v in kw.iteritems():
-        if v is None:
-            query.pop(k, None)
-        else:
-            query[k] = v
-    out = web.ctx.path
-    if query:
-        out += '?' + urlencode(query)
-    return out
-
-def url(path=None, **kw):
-    """
-    Makes url by concatinating web.ctx.homepath and path and the 
-    query string created using the arguments.
-    """
-    if path is None:
-        path = web.ctx.path
-    if path.startswith("/"):
-        out = web.ctx.homepath + path
-    else:
-        out = path
-
-    if kw:
-        out += '?' + urlencode(kw)
-    
-    return out
-
-def profiler(app):
-    """Outputs basic profiling information at the bottom of each response."""
-    from utils import profile
-    def profile_internal(e, o):
-        out, result = profile(app)(e, o)
-        return list(out) + ['<pre>' + net.websafe(result) + '</pre>']
-    return profile_internal
-
-if __name__ == "__main__":
-    import doctest
-    doctest.testmod()
--- a/bundled/webpy/web/httpserver.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,225 +0,0 @@
-__all__ = ["runsimple"]
-
-import sys, os
-import webapi as web
-import net
-import utils
-
-def runbasic(func, server_address=("0.0.0.0", 8080)):
-    """
-    Runs a simple HTTP server hosting WSGI app `func`. The directory `static/` 
-    is hosted statically.
-
-    Based on [WsgiServer][ws] from [Colin Stewart][cs].
-    
-  [ws]: http://www.owlfish.com/software/wsgiutils/documentation/wsgi-server-api.html
-  [cs]: http://www.owlfish.com/
-    """
-    # Copyright (c) 2004 Colin Stewart (http://www.owlfish.com/)
-    # Modified somewhat for simplicity
-    # Used under the modified BSD license:
-    # http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
-
-    import SimpleHTTPServer, SocketServer, BaseHTTPServer, urlparse
-    import socket, errno
-    import traceback
-
-    class WSGIHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
-        def run_wsgi_app(self):
-            protocol, host, path, parameters, query, fragment = \
-                urlparse.urlparse('http://dummyhost%s' % self.path)
-
-            # we only use path, query
-            env = {'wsgi.version': (1, 0)
-                   ,'wsgi.url_scheme': 'http'
-                   ,'wsgi.input': self.rfile
-                   ,'wsgi.errors': sys.stderr
-                   ,'wsgi.multithread': 1
-                   ,'wsgi.multiprocess': 0
-                   ,'wsgi.run_once': 0
-                   ,'REQUEST_METHOD': self.command
-                   ,'REQUEST_URI': self.path
-                   ,'PATH_INFO': path
-                   ,'QUERY_STRING': query
-                   ,'CONTENT_TYPE': self.headers.get('Content-Type', '')
-                   ,'CONTENT_LENGTH': self.headers.get('Content-Length', '')
-                   ,'REMOTE_ADDR': self.client_address[0]
-                   ,'SERVER_NAME': self.server.server_address[0]
-                   ,'SERVER_PORT': str(self.server.server_address[1])
-                   ,'SERVER_PROTOCOL': self.request_version
-                   }
-
-            for http_header, http_value in self.headers.items():
-                env ['HTTP_%s' % http_header.replace('-', '_').upper()] = \
-                    http_value
-
-            # Setup the state
-            self.wsgi_sent_headers = 0
-            self.wsgi_headers = []
-
-            try:
-                # We have there environment, now invoke the application
-                result = self.server.app(env, self.wsgi_start_response)
-                try:
-                    try:
-                        for data in result:
-                            if data: 
-                                self.wsgi_write_data(data)
-                    finally:
-                        if hasattr(result, 'close'): 
-                            result.close()
-                except socket.error, socket_err:
-                    # Catch common network errors and suppress them
-                    if (socket_err.args[0] in \
-                       (errno.ECONNABORTED, errno.EPIPE)): 
-                        return
-                except socket.timeout, socket_timeout: 
-                    return
-            except:
-                print >> web.debug, traceback.format_exc(),
-
-            if (not self.wsgi_sent_headers):
-                # We must write out something!
-                self.wsgi_write_data(" ")
-            return
-
-        do_POST = run_wsgi_app
-        do_PUT = run_wsgi_app
-        do_DELETE = run_wsgi_app
-
-        def do_GET(self):
-            if self.path.startswith('/static/'):
-                SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self)
-            else:
-                self.run_wsgi_app()
-
-        def wsgi_start_response(self, response_status, response_headers, 
-                              exc_info=None):
-            if (self.wsgi_sent_headers):
-                raise Exception \
-                      ("Headers already sent and start_response called again!")
-            # Should really take a copy to avoid changes in the application....
-            self.wsgi_headers = (response_status, response_headers)
-            return self.wsgi_write_data
-
-        def wsgi_write_data(self, data):
-            if (not self.wsgi_sent_headers):
-                status, headers = self.wsgi_headers
-                # Need to send header prior to data
-                status_code = status[:status.find(' ')]
-                status_msg = status[status.find(' ') + 1:]
-                self.send_response(int(status_code), status_msg)
-                for header, value in headers:
-                    self.send_header(header, value)
-                self.end_headers()
-                self.wsgi_sent_headers = 1
-            # Send the data
-            self.wfile.write(data)
-
-    class WSGIServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
-        def __init__(self, func, server_address):
-            BaseHTTPServer.HTTPServer.__init__(self, 
-                                               server_address, 
-                                               WSGIHandler)
-            self.app = func
-            self.serverShuttingDown = 0
-
-    print "http://%s:%d/" % server_address
-    WSGIServer(func, server_address).serve_forever()
-
-def runsimple(func, server_address=("0.0.0.0", 8080)):
-    """
-    Runs [CherryPy][cp] WSGI server hosting WSGI app `func`. 
-    The directory `static/` is hosted statically.
-
-    [cp]: http://www.cherrypy.org
-    """
-    from wsgiserver import CherryPyWSGIServer
-    from SimpleHTTPServer import SimpleHTTPRequestHandler
-    from BaseHTTPServer import BaseHTTPRequestHandler
-
-    class StaticApp(SimpleHTTPRequestHandler):
-        """WSGI application for serving static files."""
-        def __init__(self, environ, start_response):
-            self.headers = []
-            self.environ = environ
-            self.start_response = start_response
-
-        def send_response(self, status, msg=""):
-            self.status = str(status) + " " + msg
-
-        def send_header(self, name, value):
-            self.headers.append((name, value))
-
-        def end_headers(self):
-            pass
-
-        def log_message(*a): pass
-
-        def __iter__(self):
-            environ = self.environ
-
-            self.path = environ.get('PATH_INFO', '')
-            self.client_address = environ.get('REMOTE_ADDR','-'), \
-                                  environ.get('REMOTE_PORT','-')
-            self.command = environ.get('REQUEST_METHOD', '-')
-
-            from cStringIO import StringIO
-            self.wfile = StringIO() # for capturing error
-
-            f = self.send_head()
-            self.start_response(self.status, self.headers)
-
-            if f:
-                block_size = 16 * 1024
-                while True:
-                    buf = f.read(block_size)
-                    if not buf:
-                        break
-                    yield buf
-                f.close()
-            else:
-                value = self.wfile.getvalue()
-                yield value
-                    
-    class WSGIWrapper(BaseHTTPRequestHandler):
-        """WSGI wrapper for logging the status and serving static files."""
-        def __init__(self, app):
-            self.app = app
-            self.format = '%s - - [%s] "%s %s %s" - %s'
-
-        def __call__(self, environ, start_response):
-            def xstart_response(status, response_headers, *args):
-                write = start_response(status, response_headers, *args)
-                self.log(status, environ)
-                return write
-
-            path = environ.get('PATH_INFO', '')
-            if path.startswith('/static/'):
-                return StaticApp(environ, xstart_response)
-            else:
-                return self.app(environ, xstart_response)
-
-        def log(self, status, environ):
-            outfile = environ.get('wsgi.errors', web.debug)
-            req = environ.get('PATH_INFO', '_')
-            protocol = environ.get('ACTUAL_SERVER_PROTOCOL', '-')
-            method = environ.get('REQUEST_METHOD', '-')
-            host = "%s:%s" % (environ.get('REMOTE_ADDR','-'), 
-                              environ.get('REMOTE_PORT','-'))
-
-            #@@ It is really bad to extend from 
-            #@@ BaseHTTPRequestHandler just for this method
-            time = self.log_date_time_string()
-
-            msg = self.format % (host, time, protocol, method, req, status)
-            print >> outfile, utils.safestr(msg)
-            
-    func = WSGIWrapper(func)
-    server = CherryPyWSGIServer(server_address, func, server_name="localhost")
-
-    print "http://%s:%d/" % server_address
-    try:
-        server.start()
-    except KeyboardInterrupt:
-        server.stop()
--- a/bundled/webpy/web/net.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,190 +0,0 @@
-"""
-Network Utilities
-(from web.py)
-"""
-
-__all__ = [
-  "validipaddr", "validipport", "validip", "validaddr", 
-  "urlquote",
-  "httpdate", "parsehttpdate", 
-  "htmlquote", "htmlunquote", "websafe",
-]
-
-import urllib, time
-try: import datetime
-except ImportError: pass
-
-def validipaddr(address):
-    """
-    Returns True if `address` is a valid IPv4 address.
-    
-        >>> validipaddr('192.168.1.1')
-        True
-        >>> validipaddr('192.168.1.800')
-        False
-        >>> validipaddr('192.168.1')
-        False
-    """
-    try:
-        octets = address.split('.')
-        if len(octets) != 4:
-            return False
-        for x in octets:
-            if not (0 <= int(x) <= 255):
-                return False
-    except ValueError:
-        return False
-    return True
-
-def validipport(port):
-    """
-    Returns True if `port` is a valid IPv4 port.
-    
-        >>> validipport('9000')
-        True
-        >>> validipport('foo')
-        False
-        >>> validipport('1000000')
-        False
-    """
-    try:
-        if not (0 <= int(port) <= 65535):
-            return False
-    except ValueError:
-        return False
-    return True
-
-def validip(ip, defaultaddr="0.0.0.0", defaultport=8080):
-    """Returns `(ip_address, port)` from string `ip_addr_port`"""
-    addr = defaultaddr
-    port = defaultport
-    
-    ip = ip.split(":", 1)
-    if len(ip) == 1:
-        if not ip[0]:
-            pass
-        elif validipaddr(ip[0]):
-            addr = ip[0]
-        elif validipport(ip[0]):
-            port = int(ip[0])
-        else:
-            raise ValueError, ':'.join(ip) + ' is not a valid IP address/port'
-    elif len(ip) == 2:
-        addr, port = ip
-        if not validipaddr(addr) and validipport(port):
-            raise ValueError, ':'.join(ip) + ' is not a valid IP address/port'
-        port = int(port)
-    else:
-        raise ValueError, ':'.join(ip) + ' is not a valid IP address/port'
-    return (addr, port)
-
-def validaddr(string_):
-    """
-    Returns either (ip_address, port) or "/path/to/socket" from string_
-    
-        >>> validaddr('/path/to/socket')
-        '/path/to/socket'
-        >>> validaddr('8000')
-        ('0.0.0.0', 8000)
-        >>> validaddr('127.0.0.1')
-        ('127.0.0.1', 8080)
-        >>> validaddr('127.0.0.1:8000')
-        ('127.0.0.1', 8000)
-        >>> validaddr('fff')
-        Traceback (most recent call last):
-            ...
-        ValueError: fff is not a valid IP address/port
-    """
-    if '/' in string_:
-        return string_
-    else:
-        return validip(string_)
-
-def urlquote(val):
-    """
-    Quotes a string for use in a URL.
-    
-        >>> urlquote('://?f=1&j=1')
-        '%3A//%3Ff%3D1%26j%3D1'
-        >>> urlquote(None)
-        ''
-        >>> urlquote(u'\u203d')
-        '%E2%80%BD'
-    """
-    if val is None: return ''
-    if not isinstance(val, unicode): val = str(val)
-    else: val = val.encode('utf-8')
-    return urllib.quote(val)
-
-def httpdate(date_obj):
-    """
-    Formats a datetime object for use in HTTP headers.
-    
-        >>> import datetime
-        >>> httpdate(datetime.datetime(1970, 1, 1, 1, 1, 1))
-        'Thu, 01 Jan 1970 01:01:01 GMT'
-    """
-    return date_obj.strftime("%a, %d %b %Y %H:%M:%S GMT")
-
-def parsehttpdate(string_):
-    """
-    Parses an HTTP date into a datetime object.
-
-        >>> parsehttpdate('Thu, 01 Jan 1970 01:01:01 GMT')
-        datetime.datetime(1970, 1, 1, 1, 1, 1)
-    """
-    try:
-        t = time.strptime(string_, "%a, %d %b %Y %H:%M:%S %Z")
-    except ValueError:
-        return None
-    return datetime.datetime(*t[:6])
-
-def htmlquote(text):
-    """
-    Encodes `text` for raw use in HTML.
-    
-        >>> htmlquote("<'&\\">")
-        '&lt;&#39;&amp;&quot;&gt;'
-    """
-    text = text.replace("&", "&amp;") # Must be done first!
-    text = text.replace("<", "&lt;")
-    text = text.replace(">", "&gt;")
-    text = text.replace("'", "&#39;")
-    text = text.replace('"', "&quot;")
-    return text
-
-def htmlunquote(text):
-    """
-    Decodes `text` that's HTML quoted.
-
-        >>> htmlunquote('&lt;&#39;&amp;&quot;&gt;')
-        '<\\'&">'
-    """
-    text = text.replace("&quot;", '"')
-    text = text.replace("&#39;", "'")
-    text = text.replace("&gt;", ">")
-    text = text.replace("&lt;", "<")
-    text = text.replace("&amp;", "&") # Must be done last!
-    return text
-
-def websafe(val):
-    """
-    Converts `val` so that it's safe for use in UTF-8 HTML.
-    
-        >>> websafe("<'&\\">")
-        '&lt;&#39;&amp;&quot;&gt;'
-        >>> websafe(None)
-        ''
-        >>> websafe(u'\u203d')
-        '\\xe2\\x80\\xbd'
-    """
-    if val is None:
-        return ''
-    if isinstance(val, unicode):
-        val = val.encode('utf-8')
-    val = str(val)
-    return htmlquote(val)
-
-if __name__ == "__main__":
-    import doctest
-    doctest.testmod()
--- a/bundled/webpy/web/session.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,319 +0,0 @@
-"""
-Session Management
-(from web.py)
-"""
-
-import os, time, datetime, random, base64
-try:
-    import cPickle as pickle
-except ImportError:
-    import pickle
-try:
-    import hashlib
-    sha1 = hashlib.sha1
-except ImportError:
-    import sha
-    sha1 = sha.new
-
-import utils
-import webapi as web
-
-__all__ = [
-    'Session', 'SessionExpired',
-    'Store', 'DiskStore', 'DBStore',
-]
-
-web.config.session_parameters = utils.storage({
-    'cookie_name': 'webpy_session_id',
-    'cookie_domain': None,
-    'timeout': 86400, #24 * 60 * 60, # 24 hours in seconds
-    'ignore_expiry': True,
-    'ignore_change_ip': True,
-    'secret_key': 'fLjUfxqXtfNoIldA0A0J',
-    'expired_message': 'Session expired',
-})
-
-class SessionExpired(web.HTTPError): 
-    def __init__(self, message):
-        web.HTTPError.__init__(self, '200 OK', {}, data=message)
-
-class Session(utils.ThreadedDict):
-    """Session management for web.py
-    """
-
-    def __init__(self, app, store, initializer=None):
-        self.__dict__['store'] = store
-        self.__dict__['_initializer'] = initializer
-        self.__dict__['_last_cleanup_time'] = 0
-        self.__dict__['_config'] = utils.storage(web.config.session_parameters)
-
-        if app:
-            app.add_processor(self._processor)
-
-    def _processor(self, handler):
-        """Application processor to setup session for every request"""
-        self._cleanup()
-        self._load()
-
-        try:
-            return handler()
-        finally:
-            self._save()
-
-    def _load(self):
-        """Load the session from the store, by the id from cookie"""
-        cookie_name = self._config.cookie_name
-        cookie_domain = self._config.cookie_domain
-        self.session_id = web.cookies().get(cookie_name)
-
-        # protection against session_id tampering
-        if self.session_id and not self._valid_session_id(self.session_id):
-            self.session_id = None
-
-        self._check_expiry()
-        if self.session_id:
-            d = self.store[self.session_id]
-            self.update(d)
-            self._validate_ip()
-        
-        if not self.session_id:
-            self.session_id = self._generate_session_id()
-
-            if self._initializer:
-                if isinstance(self._initializer, dict):
-                    self.update(self._initializer)
-                elif hasattr(self._initializer, '__call__'):
-                    self._initializer()
- 
-        self.ip = web.ctx.ip
-
-    def _check_expiry(self):
-        # check for expiry
-        if self.session_id and self.session_id not in self.store:
-            if self._config.ignore_expiry:
-                self.session_id = None
-            else:
-                return self.expired()
-
-    def _validate_ip(self):
-        # check for change of IP
-        if self.session_id and self.get('ip', None) != web.ctx.ip:
-            if not self._config.ignore_change_ip:
-               return self.expired() 
-    
-    def _save(self):
-        cookie_name = self._config.cookie_name
-        cookie_domain = self._config.cookie_domain
-        if not self.get('_killed'):
-            web.setcookie(cookie_name, self.session_id, domain=cookie_domain)
-            self.store[self.session_id] = dict(self)
-        else:
-            web.setcookie(cookie_name, self.session_id, expires=-1, domain=cookie_domain)
-    
-    def _generate_session_id(self):
-        """Generate a random id for session"""
-
-        while True:
-            rand = os.urandom(16)
-            now = time.time()
-            secret_key = self._config.secret_key
-            session_id = sha1("%s%s%s%s" %(rand, now, utils.safestr(web.ctx.ip), secret_key))
-            session_id = session_id.hexdigest()
-            if session_id not in self.store:
-                break
-        return session_id
-
-    def _valid_session_id(self, session_id):
-        rx = utils.re_compile('^[0-9a-fA-F]+$')
-        return rx.match(session_id)
-        
-    def _cleanup(self):
-        """Cleanup the stored sessions"""
-        current_time = time.time()
-        timeout = self._config.timeout
-        if current_time - self._last_cleanup_time > timeout:
-            self.store.cleanup(timeout)
-            self.__dict__['_last_cleanup_time'] = current_time
-
-    def expired(self):
-        """Called when an expired session is atime"""
-        self._killed = True
-        self._save()
-        raise SessionExpired(self._config.expired_message)
- 
-    def kill(self):
-        """Kill the session, make it no longer available"""
-        del self.store[self.session_id]
-        self._killed = True
-
-class Store:
-    """Base class for session stores"""
-
-    def __contains__(self, key):
-        raise NotImplementedError
-
-    def __getitem__(self, key):
-        raise NotImplementedError
-
-    def __setitem__(self, key, value):
-        raise NotImplementedError
-
-    def cleanup(self, timeout):
-        """removes all the expired sessions"""
-        raise NotImplementedError
-
-    def encode(self, session_dict):
-        """encodes session dict as a string"""
-        pickled = pickle.dumps(session_dict)
-        return base64.encodestring(pickled)
-
-    def decode(self, session_data):
-        """decodes the data to get back the session dict """
-        pickled = base64.decodestring(session_data)
-        return pickle.loads(pickled)
-
-class DiskStore(Store):
-    """
-    Store for saving a session on disk.
-
-        >>> import tempfile
-        >>> root = tempfile.mkdtemp()
-        >>> s = DiskStore(root)
-        >>> s['a'] = 'foo'
-        >>> s['a']
-        'foo'
-        >>> time.sleep(0.01)
-        >>> s.cleanup(0.01)
-        >>> s['a']
-        Traceback (most recent call last):
-            ...
-        KeyError: 'a'
-    """
-    def __init__(self, root):
-        # if the storage root doesn't exists, create it.
-        if not os.path.exists(root):
-            os.mkdir(root)
-        self.root = root
-
-    def _get_path(self, key):
-        if os.path.sep in key: 
-            raise ValueError, "Bad key: %s" % repr(key)
-        return os.path.join(self.root, key)
-    
-    def __contains__(self, key):
-        path = self._get_path(key)
-        return os.path.exists(path)
-
-    def __getitem__(self, key):
-        path = self._get_path(key)
-        if os.path.exists(path): 
-            pickled = open(path).read()
-            return self.decode(pickled)
-        else:
-            raise KeyError, key
-
-    def __setitem__(self, key, value):
-        path = self._get_path(key)
-        pickled = self.encode(value)    
-        try:
-            f = open(path, 'w')
-            try:
-                f.write(pickled)
-            finally: 
-                f.close()
-        except IOError:
-            pass
-
-    def __delitem__(self, key):
-        path = self._get_path(key)
-        if os.path.exists(path):
-            os.remove(path)
-    
-    def cleanup(self, timeout):
-        now = time.time()
-        for f in os.listdir(self.root):
-            path = self._get_path(f)
-            atime = os.stat(path).st_atime
-            if now - atime > timeout :
-                os.remove(path)
-
-class DBStore(Store):
-    """Store for saving a session in database
-    Needs a table with the following columns:
-
-        session_id CHAR(128) UNIQUE NOT NULL,
-        atime DATETIME NOT NULL default current_timestamp,
-        data TEXT
-    """
-    def __init__(self, db, table_name):
-        self.db = db
-        self.table = table_name
-    
-    def __contains__(self, key):
-        data = self.db.select(self.table, where="session_id=$key", vars=locals())
-        return bool(list(data)) 
-
-    def __getitem__(self, key):
-        now = datetime.datetime.now()
-        try:
-            s = self.db.select(self.table, where="session_id=$key", vars=locals())[0]
-            self.db.update(self.table, where="session_id=$key", atime=now, vars=locals())
-        except IndexError:
-            raise KeyError
-        else:
-            return self.decode(s.data)
-
-    def __setitem__(self, key, value):
-        pickled = self.encode(value)
-        now = datetime.datetime.now()
-        if key in self:
-            self.db.update(self.table, where="session_id=$key", data=pickled, vars=locals())
-        else:
-            self.db.insert(self.table, False, session_id=key, data=pickled )
-                
-    def __delitem__(self, key):
-        self.db.delete(self.table, where="session_id=$key", vars=locals())
-
-    def cleanup(self, timeout):
-        timeout = datetime.timedelta(timeout/(24.0*60*60)) #timedelta takes numdays as arg
-        last_allowed_time = datetime.datetime.now() - timeout
-        self.db.delete(self.table, where="$last_allowed_time > atime", vars=locals())
-
-class ShelfStore:
-    """Store for saving session using `shelve` module.
-
-        import shelve
-        store = ShelfStore(shelve.open('session.shelf'))
-
-    XXX: is shelve thread-safe?
-    """
-    def __init__(self, shelf):
-        self.shelf = shelf
-
-    def __contains__(self, key):
-        return key in self.shelf
-
-    def __getitem__(self, key):
-        atime, v = self.shelf[key]
-        self[key] = v # update atime
-        return v
-
-    def __setitem__(self, key, value):
-        self.shelf[key] = time.time(), value
-        
-    def __delitem__(self, key):
-        try:
-            del self.shelf[key]
-        except KeyError:
-            pass
-
-    def cleanup(self, timeout):
-        now = time.time()
-        for k in self.shelf.keys():
-            atime, v = self.shelf[k]
-            if now - atime > timeout :
-                del self[k]
-
-if __name__ == '__main__' :
-    import doctest
-    doctest.testmod()
--- a/bundled/webpy/web/template.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1412 +0,0 @@
-"""
-simple, elegant templating
-(part of web.py)
-
-Template design:
-
-Template string is split into tokens and the tokens are combined into nodes. 
-Parse tree is a nodelist. TextNode and ExpressionNode are simple nodes and 
-for-loop, if-loop etc are block nodes, which contain multiple child nodes. 
-
-Each node can emit some python string. python string emitted by the 
-root node is validated for safeeval and executed using python in the given environment.
-
-Enough care is taken to make sure the generated code and the template has line to line match, 
-so that the error messages can point to exact line number in template. (It doesn't work in some cases still.)
-
-Grammar:
-
-    template -> defwith sections 
-    defwith -> '$def with (' arguments ')' | ''
-    sections -> section*
-    section -> block | assignment | line
-
-    assignment -> '$ ' <assignment expression>
-    line -> (text|expr)*
-    text -> <any characters other than $>
-    expr -> '$' pyexpr | '$(' pyexpr ')' | '${' pyexpr '}'
-    pyexpr -> <python expression>
-
-"""
-
-__all__ = [
-    "Template",
-    "Render", "render", "frender",
-    "ParseError", "SecurityError",
-    "test"
-]
-
-import tokenize
-import os
-import glob
-import re
-
-from utils import storage, safeunicode, safestr, re_compile
-from webapi import config
-from net import websafe
-
-def splitline(text):
-    r"""
-    Splits the given text at newline.
-    
-        >>> splitline('foo\nbar')
-        ('foo\n', 'bar')
-        >>> splitline('foo')
-        ('foo', '')
-        >>> splitline('')
-        ('', '')
-    """
-    index = text.find('\n') + 1
-    if index:
-        return text[:index], text[index:]
-    else:
-        return text, ''
-
-class Parser:
-    """Parser Base.
-    """
-    def __init__(self, text, name="<template>"):
-        self.text = text
-        self.name = name
-
-    def parse(self):
-        text = self.text
-        defwith, text = self.read_defwith(text)
-        suite = self.read_suite(text)
-        return DefwithNode(defwith, suite)
-
-    def read_defwith(self, text):
-        if text.startswith('$def with'):
-            defwith, text = splitline(text)
-            defwith = defwith[1:].strip() # strip $ and spaces
-            return defwith, text
-        else:
-            return '', text
-    
-    def read_section(self, text):
-        r"""Reads one section from the given text.
-        
-        section -> block | assignment | line
-        
-            >>> read_section = Parser('').read_section
-            >>> read_section('foo\nbar\n')
-            (<line: [t'foo\n']>, 'bar\n')
-            >>> read_section('$ a = b + 1\nfoo\n')
-            (<assignment: 'a = b + 1'>, 'foo\n')
-            
-        read_section('$for in range(10):\n    hello $i\nfoo)
-        """
-        if text.lstrip(' ').startswith('$'):
-            index = text.index('$')
-            begin_indent, text2 = text[:index], text[index+1:]
-            ahead = self.python_lookahead(text2)
-            
-            if ahead == 'var':
-                return self.read_var(text2)
-            elif ahead in STATEMENT_NODES:
-                return self.read_block_section(text2, begin_indent)
-            elif ahead in KEYWORDS:
-                return self.read_keyword(text2)
-            elif ahead.strip() == '':
-                # assignments starts with a space after $
-                # ex: $ a = b + 2
-                return self.read_assignment(text2)
-        return self.readline(text)
-        
-    def read_var(self, text):
-        r"""Reads a var statement.
-        
-            >>> read_var = Parser('').read_var
-            >>> read_var('var x=10\nfoo')
-            (<var: x = 10>, 'foo')
-            >>> read_var('var x: hello $name\nfoo')
-            (<var: x = join_('hello ', escape_(name, True))>, 'foo')
-        """
-        line, text = splitline(text)
-        tokens = self.python_tokens(line)
-        if len(tokens) < 4:
-            raise SyntaxError('Invalid var statement')
-            
-        name = tokens[1]
-        sep = tokens[2]
-        value = line.split(sep, 1)[1].strip()
-        
-        if sep == '=':
-            pass # no need to process value
-        elif sep == ':': 
-            #@@ Hack for backward-compatability
-            if tokens[3] == '\n': # multi-line var statement
-                block, text = self.read_indented_block(text, '    ')
-                lines = [self.readline(x)[0] for x in block.splitlines()]
-                nodes = []
-                for x in lines:
-                    nodes.extend(x.nodes)
-                    nodes.append(TextNode('\n'))         
-            else: # single-line var statement
-                linenode, _ = self.readline(value)
-                nodes = linenode.nodes                
-            parts = [node.emit('') for node in nodes]
-            value = "join_(%s)" % ", ".join(parts)
-        else:
-            raise SyntaxError('Invalid var statement')
-        return VarNode(name, value), text
-                    
-    def read_suite(self, text):
-        r"""Reads section by section till end of text.
-        
-            >>> read_suite = Parser('').read_suite
-            >>> read_suite('hello $name\nfoo\n')
-            [<line: [t'hello ', $name, t'\n']>, <line: [t'foo\n']>]
-        """
-        sections = []
-        while text:
-            section, text = self.read_section(text)
-            sections.append(section)
-        return SuiteNode(sections)
-    
-    def readline(self, text):
-        r"""Reads one line from the text. Newline is supressed if the line ends with \.
-        
-            >>> readline = Parser('').readline
-            >>> readline('hello $name!\nbye!')
-            (<line: [t'hello ', $name, t'!\n']>, 'bye!')
-            >>> readline('hello $name!\\\nbye!')
-            (<line: [t'hello ', $name, t'!']>, 'bye!')
-            >>> readline('$f()\n\n')
-            (<line: [$f(), t'\n']>, '\n')
-        """
-        line, text = splitline(text)
-
-        # supress new line if line ends with \
-        if line.endswith('\\\n'):
-            line = line[:-2]
-                
-        nodes = []
-        while line:
-            node, line = self.read_node(line)
-            nodes.append(node)
-            
-        return LineNode(nodes), text
-
-    def read_node(self, text):
-        r"""Reads a node from the given text and returns the node and remaining text.
-
-            >>> read_node = Parser('').read_node
-            >>> read_node('hello $name')
-            (t'hello ', '$name')
-            >>> read_node('$name')
-            ($name, '')
-        """
-        if text.startswith('$$'):
-            return TextNode('$'), text[2:]
-        elif text.startswith('$#'): # comment
-            line, text = splitline(text)
-            return TextNode('\n'), text
-        elif text.startswith('$'):
-            text = text[1:] # strip $
-            if text.startswith(':'):
-                escape = False
-                text = text[1:] # strip :
-            else:
-                escape = True
-            return self.read_expr(text, escape=escape)
-        else:
-            return self.read_text(text)
-    
-    def read_text(self, text):
-        r"""Reads a text node from the given text.
-        
-            >>> read_text = Parser('').read_text
-            >>> read_text('hello $name')
-            (t'hello ', '$name')
-        """
-        index = text.find('$')
-        if index < 0:
-            return TextNode(text), ''
-        else:
-            return TextNode(text[:index]), text[index:]
-            
-    def read_keyword(self, text):
-        line, text = splitline(text)
-        return CodeNode(None, line.strip() + "\n"), text
-
-    def read_expr(self, text, escape=True):
-        """Reads a python expression from the text and returns the expression and remaining text.
-
-        expr -> simple_expr | paren_expr
-        simple_expr -> id extended_expr
-        extended_expr -> attr_access | paren_expr extended_expr | ''
-        attr_access -> dot id extended_expr
-        paren_expr -> [ tokens ] | ( tokens ) | { tokens }
-     
-            >>> read_expr = Parser('').read_expr
-            >>> read_expr("name")
-            ($name, '')
-            >>> read_expr("a.b and c")
-            ($a.b, ' and c')
-            >>> read_expr("a. b")
-            ($a, '. b')
-            >>> read_expr("name</h1>")
-            ($name, '</h1>')
-            >>> read_expr("(limit)ing")
-            ($(limit), 'ing')
-            >>> read_expr('a[1, 2][:3].f(1+2, "weird string[).", 3 + 4) done.')
-            ($a[1, 2][:3].f(1+2, "weird string[).", 3 + 4), ' done.')
-        """
-        def simple_expr():
-            identifier()
-            extended_expr()
-        
-        def identifier():
-            tokens.next()
-        
-        def extended_expr():
-            lookahead = tokens.lookahead()
-            if lookahead is None:
-                return
-            elif lookahead.value == '.':
-                attr_access()
-            elif lookahead.value in parens:
-                paren_expr()
-                extended_expr()
-            else:
-                return
-        
-        def attr_access():
-            from token import NAME # python token constants
-            dot = tokens.lookahead()
-            if tokens.lookahead2().type == NAME:
-                tokens.next() # consume dot
-                identifier()
-                extended_expr()
-        
-        def paren_expr():
-            begin = tokens.next().value
-            end = parens[begin]
-            while True:
-                if tokens.lookahead().value in parens:
-                    paren_expr()
-                else:
-                    t = tokens.next()
-                    if t.value == end:
-                        break
-            return
-
-        parens = {
-            "(": ")",
-            "[": "]",
-            "{": "}"
-        }
-        
-        def get_tokens(text):
-            """tokenize text using python tokenizer.
-            Python tokenizer ignores spaces, but they might be important in some cases. 
-            This function introduces dummy space tokens when it identifies any ignored space.
-            Each token is a storage object containing type, value, begin and end.
-            """
-            readline = iter([text]).next
-            end = None
-            for t in tokenize.generate_tokens(readline):
-                t = storage(type=t[0], value=t[1], begin=t[2], end=t[3])
-                if end is not None and end != t.begin:
-                    _, x1 = end
-                    _, x2 = t.begin
-                    yield storage(type=-1, value=text[x1:x2], begin=end, end=t.begin)
-                end = t.end
-                yield t
-                
-        class BetterIter:
-            """Iterator like object with 2 support for 2 look aheads."""
-            def __init__(self, items):
-                self.iteritems = iter(items)
-                self.items = []
-                self.position = 0
-                self.current_item = None
-            
-            def lookahead(self):
-                if len(self.items) <= self.position:
-                    self.items.append(self._next())
-                return self.items[self.position]
-
-            def _next(self):
-                try:
-                    return self.iteritems.next()
-                except StopIteration:
-                    return None
-                
-            def lookahead2(self):
-                if len(self.items) <= self.position+1:
-                    self.items.append(self._next())
-                return self.items[self.position+1]
-                    
-            def next(self):
-                self.current_item = self.lookahead()
-                self.position += 1
-                return self.current_item
-
-        tokens = BetterIter(get_tokens(text))
-                
-        if tokens.lookahead().value in parens:
-            paren_expr()
-        else:
-            simple_expr()
-        row, col = tokens.current_item.end
-        return ExpressionNode(text[:col], escape=escape), text[col:]    
-
-    def read_assignment(self, text):
-        r"""Reads assignment statement from text.
-    
-            >>> read_assignment = Parser('').read_assignment
-            >>> read_assignment('a = b + 1\nfoo')
-            (<assignment: 'a = b + 1'>, 'foo')
-        """
-        line, text = splitline(text)
-        return AssignmentNode(line.strip()), text
-    
-    def python_lookahead(self, text):
-        """Returns the first python token from the given text.
-        
-            >>> python_lookahead = Parser('').python_lookahead
-            >>> python_lookahead('for i in range(10):')
-            'for'
-            >>> python_lookahead('else:')
-            'else'
-            >>> python_lookahead(' x = 1')
-            ' '
-        """
-        readline = iter([text]).next
-        tokens = tokenize.generate_tokens(readline)
-        return tokens.next()[1]
-        
-    def python_tokens(self, text):
-        readline = iter([text]).next
-        tokens = tokenize.generate_tokens(readline)
-        return [t[1] for t in tokens]
-        
-    def read_indented_block(self, text, indent):
-        r"""Read a block of text. A block is what typically follows a for or it statement.
-        It can be in the same line as that of the statement or an indented block.
-
-            >>> read_indented_block = Parser('').read_indented_block
-            >>> read_indented_block('  a\n  b\nc', '  ')
-            ('a\nb\n', 'c')
-            >>> read_indented_block('  a\n    b\n  c\nd', '  ')
-            ('a\n  b\nc\n', 'd')
-        """
-        if indent == '':
-            return '', text
-            
-        block = ""
-        while True:
-            if text.startswith(indent):
-                line, text = splitline(text)
-                block += line[len(indent):]
-            else:
-                break
-        return block, text
-
-    def read_statement(self, text):
-        r"""Reads a python statement.
-        
-            >>> read_statement = Parser('').read_statement
-            >>> read_statement('for i in range(10): hello $name')
-            ('for i in range(10):', ' hello $name')
-        """
-        tok = PythonTokenizer(text)
-        tok.consume_till(':')
-        return text[:tok.index], text[tok.index:]
-        
-    def read_block_section(self, text, begin_indent=''):
-        r"""
-            >>> read_block_section = Parser('').read_block_section
-            >>> read_block_section('for i in range(10): hello $i\nfoo')
-            (<block: 'for i in range(10):', [<line: [t'hello ', $i, t'\n']>]>, 'foo')
-            >>> read_block_section('for i in range(10):\n        hello $i\n    foo', begin_indent='    ')
-            (<block: 'for i in range(10):', [<line: [t'hello ', $i, t'\n']>]>, '    foo')
-            >>> read_block_section('for i in range(10):\n  hello $i\nfoo')
-            (<block: 'for i in range(10):', [<line: [t'hello ', $i, t'\n']>]>, 'foo')
-        """
-        line, text = splitline(text)
-        stmt, line = self.read_statement(line)
-        keyword = self.python_lookahead(stmt)
-        
-        # if there is some thing left in the line
-        if line.strip():
-            block = line.lstrip()
-        else:
-            def find_indent(text):
-                rx = re_compile('  +')
-                match = rx.match(text)    
-                first_indent = match and match.group(0)
-                return first_indent or ""
-
-            # find the indentation of the block by looking at the first line
-            first_indent = find_indent(text)[len(begin_indent):]
-            indent = begin_indent + min(first_indent, INDENT)
-            
-            block, text = self.read_indented_block(text, indent)
-            
-        return self.create_block_node(keyword, stmt, block, begin_indent), text
-        
-    def create_block_node(self, keyword, stmt, block, begin_indent):
-        if keyword in STATEMENT_NODES:
-            return STATEMENT_NODES[keyword](stmt, block, begin_indent)
-        else:
-            raise ParseError, 'Unknown statement: %s' % repr(keyword)
-        
-class PythonTokenizer:
-    """Utility wrapper over python tokenizer."""
-    def __init__(self, text):
-        self.text = text
-        readline = iter([text]).next
-        self.tokens = tokenize.generate_tokens(readline)
-        self.index = 0
-        
-    def consume_till(self, delim):        
-        """Consumes tokens till colon.
-        
-            >>> tok = PythonTokenizer('for i in range(10): hello $i')
-            >>> tok.consume_till(':')
-            >>> tok.text[:tok.index]
-            'for i in range(10):'
-            >>> tok.text[tok.index:]
-            ' hello $i'
-        """
-        try:
-            while True:
-                t = self.next()
-                if t.value == delim:
-                    break
-                elif t.value == '(':
-                    self.consume_till(')')
-                elif t.value == '[':
-                    self.consume_till(']')
-                elif t.value == '{':
-                    self.consume_till('}')
-
-                # if end of line is found, it is an exception.
-                # Since there is no easy way to report the line number,
-                # leave the error reporting to the python parser later  
-                #@@ This should be fixed.
-                if t.value == '\n':
-                    break
-        except:
-            #raise ParseError, "Expected %s, found end of line." % repr(delim)
-
-            # raising ParseError doesn't show the line number. 
-            # if this error is ignored, then it will be caught when compiling the python code.
-            return
-    
-    def next(self):
-        type, t, begin, end, line = self.tokens.next()
-        row, col = end
-        self.index = col
-        return storage(type=type, value=t, begin=begin, end=end)
-        
-class DefwithNode:
-    def __init__(self, defwith, suite):
-        if defwith:
-            self.defwith = defwith.replace('with', '__template__') + ':'
-        else:
-            self.defwith = 'def __template__():'
-        self.suite = suite
-
-    def emit(self, indent):
-        return self.defwith + self.suite.emit(indent + INDENT)
-
-    def __repr__(self):
-        return "<defwith: %s, %s>" % (self.defwith, self.nodes)
-
-class TextNode:
-    def __init__(self, value):
-        self.value = value
-
-    def emit(self, indent):
-        return repr(self.value)
-        
-    def __repr__(self):
-        return 't' + repr(self.value)
-        
-class ExpressionNode:
-    def __init__(self, value, escape=True):
-        self.value = value.strip()
-        
-        # convert ${...} to $(...)
-        if value.startswith('{') and value.endswith('}'):
-            self.value = '(' + self.value[1:-1] + ')'
-            
-        self.escape = escape
-
-    def emit(self, indent):
-        return 'escape_(%s, %s)' % (self.value, bool(self.escape))
-        
-    def __repr__(self):
-        if self.escape:
-            escape = ''
-        else:
-            escape = ':'
-        return "$%s%s" % (escape, self.value)
-        
-class AssignmentNode:
-    def __init__(self, code):
-        self.code = code
-        
-    def emit(self, indent, begin_indent=''):
-        return indent + self.code + "\n"
-        
-    def __repr__(self):
-        return "<assignment: %s>" % repr(self.code)
-        
-class LineNode:
-    def __init__(self, nodes):
-        self.nodes = nodes
-        
-    def emit(self, indent, text_indent='', name=''):
-        text = [node.emit('') for node in self.nodes]
-        if text_indent:
-            text = [repr(text_indent)] + text
-        return indent + 'yield %s, join_(%s)\n' % (repr(name), ', '.join(text))
-    
-    def __repr__(self):
-        return "<line: %s>" % repr(self.nodes)
-
-INDENT = '    ' # 4 spaces
-        
-class BlockNode:
-    def __init__(self, stmt, block, begin_indent=''):
-        self.stmt = stmt
-        self.suite = Parser('').read_suite(block)
-        self.begin_indent = begin_indent
-
-    def emit(self, indent, text_indent=''):
-        text_indent = self.begin_indent + text_indent
-        out = indent + self.stmt + self.suite.emit(indent + INDENT, text_indent)
-        return out
-        
-    def text(self):
-        return '${' + self.stmt + '}' + "".join([node.text(indent) for node in self.nodes])
-        
-    def __repr__(self):
-        return "<block: %s, %s>" % (repr(self.stmt), repr(self.nodelist))
-
-class ForNode(BlockNode):
-    def __init__(self, stmt, block, begin_indent=''):
-        self.original_stmt = stmt
-        tok = PythonTokenizer(stmt)
-        tok.consume_till('in')
-        a = stmt[:tok.index] # for i in
-        b = stmt[tok.index:-1] # rest of for stmt excluding :
-        stmt = a + ' loop.setup(' + b.strip() + '):'
-        BlockNode.__init__(self, stmt, block, begin_indent)
-        
-    def __repr__(self):
-        return "<block: %s, %s>" % (repr(self.original_stmt), repr(self.suite))
-
-class CodeNode:
-    def __init__(self, stmt, block, begin_indent=''):
-        self.code = block
-        
-    def emit(self, indent, text_indent=''):
-        import re
-        rx = re.compile('^', re.M)
-        return rx.sub(indent, self.code).rstrip(' ')
-        
-    def __repr__(self):
-        return "<code: %s>" % repr(self.code)
-        
-class IfNode(BlockNode):
-    pass
-
-class ElseNode(BlockNode):
-    pass
-
-class ElifNode(BlockNode):
-    pass
-
-class DefNode(BlockNode):
-    pass
-
-class VarNode:
-    def __init__(self, name, value):
-        self.name = name
-        self.value = value
-        
-    def emit(self, indent, text_indent):
-        return indent + 'yield %s, %s\n' % (repr(self.name), self.value)
-        
-    def __repr__(self):
-        return "<var: %s = %s>" % (self.name, self.value)
-
-class SuiteNode:
-    """Suite is a list of sections."""
-    def __init__(self, sections):
-        self.sections = sections
-        
-    def emit(self, indent, text_indent=''):
-        return "\n" + "".join([s.emit(indent, text_indent) for s in self.sections])
-        
-    def __repr__(self):
-        return repr(self.sections)
-
-STATEMENT_NODES = {
-    'for': ForNode,
-    'while': BlockNode,
-    'if': IfNode,
-    'elif': ElifNode,
-    'else': ElseNode,
-    'def': DefNode,
-    'code': CodeNode
-}
-
-KEYWORDS = [
-    "pass",
-    "break",
-    "continue",
-    "return"
-]
-
-TEMPLATE_BUILTIN_NAMES = [
-    "dict", "enumerate", "float", "int", "bool", "list", "long", "reversed", 
-    "set", "slice", "tuple", "xrange",
-    "abs", "all", "any", "callable", "chr", "cmp", "divmod", "filter", "hex", 
-    "id", "isinstance", "iter", "len", "max", "min", "oct", "ord", "pow", "range",
-    "True", "False",
-    "None",
-    "__import__", # some c-libraries like datetime requires __import__ to present in the namespace
-]
-
-import __builtin__
-TEMPLATE_BUILTINS = dict([(name, getattr(__builtin__, name)) for name in TEMPLATE_BUILTIN_NAMES if name in __builtin__.__dict__])
-
-class ForLoop:
-    """
-    Wrapper for expression in for stament to support loop.xxx helpers.
-    
-        >>> loop = ForLoop()
-        >>> for x in loop.setup(['a', 'b', 'c']):
-        ...     print loop.index, loop.revindex, loop.parity, x
-        ...
-        1 3 odd a
-        2 2 even b
-        3 1 odd c
-        >>> loop.index
-        Traceback (most recent call last):
-            ...
-        AttributeError: index
-    """
-    def __init__(self):
-        self._ctx = None
-        
-    def __getattr__(self, name):
-        if self._ctx is None:
-            raise AttributeError, name
-        else:
-            return getattr(self._ctx, name)
-        
-    def setup(self, seq):        
-        self._push()
-        return self._ctx.setup(seq)
-        
-    def _push(self):
-        self._ctx = ForLoopContext(self, self._ctx)
-        
-    def _pop(self):
-        self._ctx = self._ctx.parent
-                
-class ForLoopContext:
-    """Stackable context for ForLoop to support nested for loops.
-    """
-    def __init__(self, forloop, parent):
-        self._forloop = forloop
-        self.parent = parent
-        
-    def setup(self, seq):
-        if hasattr(seq, '__len__'):
-            n = len(seq)
-        else:
-            n = 0
-            
-        self.index = 0
-        seq = iter(seq)
-        
-        # Pre python-2.5 does not support yield in try-except.
-        # This is a work-around to overcome that limitation.
-        def next(seq):
-            try:
-                return seq.next()
-            except:
-                self._forloop._pop()
-                raise
-        
-        while True:
-            self._next(self.index + 1, n)
-            yield next(seq)
-            
-    def _next(self, i, n):
-        self.index = i
-        self.index0 = i - 1
-        self.first = (i == 1)
-        self.last = (i == n)
-        self.odd = (i % 2 == 1)
-        self.even = (i % 2 == 0)
-        self.parity = ['odd', 'even'][self.even]
-        if n:
-            self.length = n
-            self.revindex0 = n - i
-            self.revindex = self.revindex0 + 1
-        
-class BaseTemplate:
-    def __init__(self, code, filename, filter, globals, builtins):
-        self.filename = filename
-        self.filter = filter
-        self._globals = globals
-        self._builtins = builtins
-        if code:
-            self.t = self._compile(code)
-        else:
-            self.t = lambda: ''
-        
-    def _compile(self, code):
-        env = self.make_env(self._globals or {}, self._builtins)
-        exec(code, env)
-        return env['__template__']
-
-    def __call__(self, *a, **kw):
-        out = self.t(*a, **kw)
-        return self._join_output(out)
-        
-    def _join_output(self, out):
-        d = TemplateResult()
-        data = []
-        
-        for name, value in out:
-            if name:
-                d[name] = value
-            else:
-                data.append(value)
-                            
-        d.__body__ = u"".join(data)
-        return d       
-
-    def make_env(self, globals, builtins):
-        return dict(globals,
-            __builtins__=builtins, 
-            loop=ForLoop(),
-            escape_=self._escape,
-            join_=self._join
-        )
-    
-    def _join(self, *items):
-        return u"".join([safeunicode(item) for item in items])
-        
-    def _escape(self, value, escape=False):
-        import types
-        if value is None: 
-            value = ''
-        elif isinstance(value, types.GeneratorType):
-            value = self._join_output(value)
-            
-        value = safeunicode(value)
-        if escape and self.filter:
-            value = self.filter(value)
-        return value
-
-class Template(BaseTemplate):
-    CONTENT_TYPES = {
-        '.html' : 'text/html; charset=utf-8',
-        '.xhtml' : 'application/xhtml+xml; charset=utf-8',
-        '.txt' : 'text/plain',
-    }
-    FILTERS = {
-        '.html': websafe,
-        '.xhtml': websafe,
-        '.xml': websafe
-    }
-    globals = {}
-    
-    def __init__(self, text, filename='<template>', filter=None, globals=None, builtins=None):
-        text = Template.normalize_text(text)
-        code = self.compile_template(text, filename)
-                
-        _, ext = os.path.splitext(filename)
-        filter = filter or self.FILTERS.get(ext, None)
-        self.content_type = self.CONTENT_TYPES.get(ext, None)
-
-        if globals is None:
-            globals = self.globals
-        if builtins is None:
-            builtins = TEMPLATE_BUILTINS
-                
-        BaseTemplate.__init__(self, code=code, filename=filename, filter=filter, globals=globals, builtins=builtins)
-        
-    def normalize_text(text):
-        """Normalizes template text by correcting \r\n, tabs and BOM chars."""
-        text = text.replace('\r\n', '\n').replace('\r', '\n').expandtabs()
-        if not text.endswith('\n'):
-            text += '\n'
-
-        # ignore BOM chars at the begining of template
-        BOM = '\xef\xbb\xbf'
-        if isinstance(text, str) and text.startswith(BOM):
-            text = text[len(BOM):]
-        
-        # support fort \$ for backward-compatibility 
-        text = text.replace(r'\$', '$$')
-        return text
-    normalize_text = staticmethod(normalize_text)
-                
-    def __call__(self, *a, **kw):
-        import webapi as web
-        if 'headers' in web.ctx and self.content_type:
-            web.header('Content-Type', self.content_type, unique=True)
-            
-        return BaseTemplate.__call__(self, *a, **kw)
-        
-    def generate_code(text, filename):
-        # parse the text
-        rootnode = Parser(text, filename).parse()
-                
-        # generate python code from the parse tree
-        code = rootnode.emit(indent="").strip()
-        return safestr(code)
-        
-    generate_code = staticmethod(generate_code)
-        
-    def compile_template(self, template_string, filename):
-        code = Template.generate_code(template_string, filename)
-    
-        def get_source_line(filename, lineno):
-            try:
-                lines = open(filename).read().splitlines()
-                return lines[lineno]
-            except:
-                return None
-        
-        try:
-            # compile the code first to report the errors, if any, with the filename
-            compiled_code = compile(code, filename, 'exec')
-        except SyntaxError, e:
-            # display template line that caused the error along with the traceback.
-            try:
-                e.msg += '\n\nTemplate traceback:\n    File %s, line %s\n        %s' % \
-                    (repr(e.filename), e.lineno, get_source_line(e.filename, e.lineno-1))
-            except: 
-                pass
-            raise
-        
-        # make sure code is safe
-        import compiler
-        ast = compiler.parse(code)
-        SafeVisitor().walk(ast, filename)
-
-        return compiled_code
-        
-class CompiledTemplate(Template):
-    def __init__(self, f, filename):
-        Template.__init__(self, '', filename)
-        self.t = f
-        
-    def compile_template(self, *a):
-        return None
-    
-    def _compile(self, *a):
-        return None
-                
-class Render:
-    """The most preferred way of using templates.
-    
-        render = web.template.render('templates')
-        print render.foo()
-        
-    Optional parameter can be `base` can be used to pass output of 
-    every template through the base template.
-    
-        render = web.template.render('templates', base='layout')
-    """
-    def __init__(self, loc='templates', cache=None, base=None, **keywords):
-        self._loc = loc
-        self._keywords = keywords
-
-        if cache is None:
-            cache = not config.get('debug', False)
-        
-        if cache:
-            self._cache = {}
-        else:
-            self._cache = None
-        
-        if base and not hasattr(base, '__call__'):
-            # make base a function, so that it can be passed to sub-renders
-            self._base = lambda page: self._template(base)(page)
-        else:
-            self._base = base
-            
-    def _lookup(self, name):
-        path = os.path.join(self._loc, name)
-        if os.path.isdir(path):
-            return 'dir', path
-        else:
-            path = self._findfile(path)
-            if path:
-                return 'file', path
-            else:
-                return 'none', None
-        
-    def _load_template(self, name):
-        kind, path = self._lookup(name)
-        
-        if kind == 'dir':
-            return Render(path, cache=self._cache is not None, base=self._base, **self._keywords)
-        elif kind == 'file':
-            return Template(open(path).read(), filename=path, **self._keywords)
-        else:
-            raise AttributeError, "No template named " + name            
-
-    def _findfile(self, path_prefix): 
-        p = [f for f in glob.glob(path_prefix + '.*') if not f.endswith('~')] # skip backup files
-        return p and p[0]
-            
-    def _template(self, name):
-        if self._cache is not None:
-            if name not in self._cache:
-                self._cache[name] = self._load_template(name)
-            return self._cache[name]
-        else:
-            return self._load_template(name)
-        
-    def __getattr__(self, name):
-        t = self._template(name)
-        if self._base and isinstance(t, Template):
-            def template(*a, **kw):
-                return self._base(t(*a, **kw))
-            return template
-        else:
-            return self._template(name)
-
-class GAE_Render(Render):
-    # Render gets over-written. make a copy here.
-    super = Render
-    def __init__(self, loc, *a, **kw):
-        GAE_Render.super.__init__(self, loc, *a, **kw)
-        
-        import types
-        if isinstance(loc, types.ModuleType):
-            self.mod = loc
-        else:
-            name = loc.rstrip('/').replace('/', '.')
-            self.mod = __import__(name, None, None, ['x'])
-
-        self.mod.__dict__.update(kw.get('builtins', TEMPLATE_BUILTINS))
-        self.mod.__dict__.update(Template.globals)
-        self.mod.__dict__.update(kw.get('globals', {}))
-
-    def _load_template(self, name):
-        t = getattr(self.mod, name)
-        import types
-        if isinstance(t, types.ModuleType):
-            return GAE_Render(t, cache=self._cache is not None, base=self._base, **self._keywords)
-        else:
-            return t
-
-render = Render
-# setup render for Google App Engine.
-try:
-    from google import appengine
-    render = Render = GAE_Render
-except ImportError:
-    pass
-        
-def frender(path, **keywords):
-    """Creates a template from the given file path.
-    """
-    return Template(open(path).read(), filename=path, **keywords)
-    
-def compile_templates(root):
-    """Compiles templates to python code."""
-    re_start = re_compile('^', re.M)
-    
-    for dirpath, dirnames, filenames in os.walk(root):
-        filenames = [f for f in filenames if not f.startswith('.') and not f.endswith('~') and not f.startswith('__init__.py')]
-
-        for d in dirnames[:]:
-            if d.startswith('.'):
-                dirnames.remove(d) # don't visit this dir
-
-        out = open(os.path.join(dirpath, '__init__.py'), 'w')
-        out.write('from web.template import CompiledTemplate, ForLoop\n\n')
-        if dirnames:
-            out.write("import " + ", ".join(dirnames))
-
-        for f in filenames:
-            path = os.path.join(dirpath, f)
-
-            if '.' in f:
-                name, _ = f.split('.', 1)
-            else:
-                name = f
-                
-            text = open(path).read()
-            text = Template.normalize_text(text)
-            code = Template.generate_code(text, path)
-            code = re_start.sub('    ', code)
-                        
-            _gen = '' + \
-            '\ndef %s():' + \
-            '\n    loop = ForLoop()' + \
-            '\n    _dummy  = CompiledTemplate(lambda: None, "dummy")' + \
-            '\n    join_ = _dummy._join' + \
-            '\n    escape_ = _dummy._escape' + \
-            '\n' + \
-            '\n%s' + \
-            '\n    return __template__'
-            
-            gen_code = _gen % (name, code)
-            out.write(gen_code)
-            out.write('\n\n')
-            out.write('%s = CompiledTemplate(%s(), %s)\n\n' % (name, name, repr(path)))
-
-            # create template to make sure it compiles
-            t = Template(open(path).read(), path)
-        out.close()
-                
-class ParseError(Exception):
-    pass
-    
-class SecurityError(Exception):
-    """The template seems to be trying to do something naughty."""
-    pass
-
-# Enumerate all the allowed AST nodes
-ALLOWED_AST_NODES = [
-    "Add", "And",
-#   "AssAttr",
-    "AssList", "AssName", "AssTuple",
-#   "Assert",
-    "Assign", "AugAssign",
-#   "Backquote",
-    "Bitand", "Bitor", "Bitxor", "Break",
-    "CallFunc","Class", "Compare", "Const", "Continue",
-    "Decorators", "Dict", "Discard", "Div",
-    "Ellipsis", "EmptyNode",
-#   "Exec",
-    "Expression", "FloorDiv", "For",
-#   "From",
-    "Function", 
-    "GenExpr", "GenExprFor", "GenExprIf", "GenExprInner",
-    "Getattr", 
-#   "Global", 
-    "If", "IfExp",
-#   "Import",
-    "Invert", "Keyword", "Lambda", "LeftShift",
-    "List", "ListComp", "ListCompFor", "ListCompIf", "Mod",
-    "Module",
-    "Mul", "Name", "Not", "Or", "Pass", "Power",
-#   "Print", "Printnl", "Raise",
-    "Return", "RightShift", "Slice", "Sliceobj",
-    "Stmt", "Sub", "Subscript",
-#   "TryExcept", "TryFinally",
-    "Tuple", "UnaryAdd", "UnarySub",
-    "While", "With", "Yield",
-]
-
-class SafeVisitor(object):
-    """
-    Make sure code is safe by walking through the AST.
-    
-    Code considered unsafe if:
-        * it has restricted AST nodes
-        * it is trying to access resricted attributes   
-        
-    Adopted from http://www.zafar.se/bkz/uploads/safe.txt (public domain, Babar K. Zafar)
-    """
-    def __init__(self):
-        "Initialize visitor by generating callbacks for all AST node types."
-        self.errors = []
-
-    def walk(self, ast, filename):
-        "Validate each node in AST and raise SecurityError if the code is not safe."
-        self.filename = filename
-        self.visit(ast)
-        
-        if self.errors:        
-            raise SecurityError, '\n'.join([str(err) for err in self.errors])
-        
-    def visit(self, node, *args):
-        "Recursively validate node and all of its children."
-        def classname(obj):
-            return obj.__class__.__name__
-        nodename = classname(node)
-        fn = getattr(self, 'visit' + nodename, None)
-        
-        if fn:
-            fn(node, *args)
-        else:
-            if nodename not in ALLOWED_AST_NODES:
-                self.fail(node, *args)
-            
-        for child in node.getChildNodes():
-            self.visit(child, *args)
-
-    def visitName(self, node, *args):
-        "Disallow any attempts to access a restricted attr."
-        #self.assert_attr(node.getChildren()[0], node)
-        pass
-        
-    def visitGetattr(self, node, *args):
-        "Disallow any attempts to access a restricted attribute."
-        self.assert_attr(node.attrname, node)
-            
-    def assert_attr(self, attrname, node):
-        if self.is_unallowed_attr(attrname):
-            lineno = self.get_node_lineno(node)
-            e = SecurityError("%s:%d - access to attribute '%s' is denied" % (self.filename, lineno, attrname))
-            self.errors.append(e)
-
-    def is_unallowed_attr(self, name):
-        return name.startswith('_') \
-            or name.startswith('func_') \
-            or name.startswith('im_')
-            
-    def get_node_lineno(self, node):
-        return (node.lineno) and node.lineno or 0
-        
-    def fail(self, node, *args):
-        "Default callback for unallowed AST nodes."
-        lineno = self.get_node_lineno(node)
-        nodename = node.__class__.__name__
-        e = SecurityError("%s:%d - execution of '%s' statements is denied" % (self.filename, lineno, nodename))
-        self.errors.append(e)
-
-class TemplateResult(storage):
-    """Dictionary like object for storing template output.
-    
-    A template can specify key-value pairs in the output using 
-    `var` statements. Each `var` statement adds a new key to the 
-    template output and the main output is stored with key 
-    __body__.
-    
-        >>> d = TemplateResult(__body__='hello, world', x='foo')
-        >>> d
-        <TemplateResult: {'__body__': 'hello, world', 'x': 'foo'}>
-        >>> print d
-        hello, world
-    """
-    def __unicode__(self): 
-        return safeunicode(self.get('__body__', ''))
-    
-    def __str__(self):
-        return safestr(self.get('__body__', ''))
-        
-    def __repr__(self):
-        return "<TemplateResult: %s>" % dict.__repr__(self)
-    
-def test():
-    r"""Doctest for testing template module.
-
-    Define a utility function to run template test.
-    
-        >>> class TestResult(TemplateResult):
-        ...     def __repr__(self): return repr(unicode(self))
-        ...
-        >>> def t(code, **keywords):
-        ...     tmpl = Template(code, **keywords)
-        ...     return lambda *a, **kw: TestResult(tmpl(*a, **kw))
-        ...
-    
-    Simple tests.
-    
-        >>> t('1')()
-        u'1\n'
-        >>> t('$def with ()\n1')()
-        u'1\n'
-        >>> t('$def with (a)\n$a')(1)
-        u'1\n'
-        >>> t('$def with (a=0)\n$a')(1)
-        u'1\n'
-        >>> t('$def with (a=0)\n$a')(a=1)
-        u'1\n'
-    
-    Test complicated expressions.
-        
-        >>> t('$def with (x)\n$x.upper()')('hello')
-        u'HELLO\n'
-        >>> t('$(2 * 3 + 4 * 5)')()
-        u'26\n'
-        >>> t('${2 * 3 + 4 * 5}')()
-        u'26\n'
-        >>> t('$def with (limit)\nkeep $(limit)ing.')('go')
-        u'keep going.\n'
-        >>> t('$def with (a)\n$a.b[0]')(storage(b=[1]))
-        u'1\n'
-        
-    Test html escaping.
-    
-        >>> t('$def with (x)\n$x', filename='a.html')('<html>')
-        u'&lt;html&gt;\n'
-        >>> t('$def with (x)\n$x', filename='a.txt')('<html>')
-        u'<html>\n'
-                
-    Test if, for and while.
-    
-        >>> t('$if 1: 1')()
-        u'1\n'
-        >>> t('$if 1:\n    1')()
-        u'1\n'
-        >>> t('$if 1:\n    1\\')()
-        u'1'
-        >>> t('$if 0: 0\n$elif 1: 1')()
-        u'1\n'
-        >>> t('$if 0: 0\n$elif None: 0\n$else: 1')()
-        u'1\n'
-        >>> t('$if 0 < 1 and 1 < 2: 1')()
-        u'1\n'
-        >>> t('$for x in [1, 2, 3]: $x')()
-        u'1\n2\n3\n'
-        >>> t('$def with (d)\n$for k, v in d.iteritems(): $k')({1: 1})
-        u'1\n'
-        >>> t('$for x in [1, 2, 3]:\n\t$x')()
-        u'    1\n    2\n    3\n'
-        >>> t('$def with (a)\n$while a and a.pop():1')([1, 2, 3])
-        u'1\n1\n1\n'
-
-    The space after : must be ignored.
-    
-        >>> t('$if True: foo')()
-        u'foo\n'
-    
-    Test loop.xxx.
-
-        >>> t("$for i in range(5):$loop.index, $loop.parity")()
-        u'1, odd\n2, even\n3, odd\n4, even\n5, odd\n'
-        >>> t("$for i in range(2):\n    $for j in range(2):$loop.parent.parity $loop.parity")()
-        u'odd odd\nodd even\neven odd\neven even\n'
-        
-    Test assignment.
-    
-        >>> t('$ a = 1\n$a')()
-        u'1\n'
-        >>> t('$ a = [1]\n$a[0]')()
-        u'1\n'
-        >>> t('$ a = {1: 1}\n$a.keys()[0]')()
-        u'1\n'
-        >>> t('$ a = []\n$if not a: 1')()
-        u'1\n'
-        >>> t('$ a = {}\n$if not a: 1')()
-        u'1\n'
-        >>> t('$ a = -1\n$a')()
-        u'-1\n'
-        >>> t('$ a = "1"\n$a')()
-        u'1\n'
-
-    Test comments.
-    
-        >>> t('$# 0')()
-        u'\n'
-        >>> t('hello$#comment1\nhello$#comment2')()
-        u'hello\nhello\n'
-        >>> t('$#comment0\nhello$#comment1\nhello$#comment2')()
-        u'\nhello\nhello\n'
-        
-    Test unicode.
-    
-        >>> t('$def with (a)\n$a')(u'\u203d')
-        u'\u203d\n'
-        >>> t('$def with (a)\n$a')(u'\u203d'.encode('utf-8'))
-        u'\u203d\n'
-        >>> t(u'$def with (a)\n$a $:a')(u'\u203d')
-        u'\u203d \u203d\n'
-        >>> t(u'$def with ()\nfoo')()
-        u'foo\n'
-        >>> def f(x): return x
-        ...
-        >>> t(u'$def with (f)\n$:f("x")')(f)
-        u'x\n'
-        >>> t('$def with (f)\n$:f("x")')(f)
-        u'x\n'
-    
-    Test dollar escaping.
-    
-        >>> t("Stop, $$money isn't evaluated.")()
-        u"Stop, $money isn't evaluated.\n"
-        >>> t("Stop, \$money isn't evaluated.")()
-        u"Stop, $money isn't evaluated.\n"
-        
-    Test space sensitivity.
-    
-        >>> t('$def with (x)\n$x')(1)
-        u'1\n'
-        >>> t('$def with(x ,y)\n$x')(1, 1)
-        u'1\n'
-        >>> t('$(1 + 2*3 + 4)')()
-        u'11\n'
-        
-    Make sure globals are working.
-            
-        >>> t('$x')()
-        Traceback (most recent call last):
-            ...
-        NameError: global name 'x' is not defined
-        >>> t('$x', globals={'x': 1})()
-        u'1\n'
-        
-    Can't change globals.
-    
-        >>> t('$ x = 2\n$x', globals={'x': 1})()
-        u'2\n'
-        >>> t('$ x = x + 1\n$x', globals={'x': 1})()
-        Traceback (most recent call last):
-            ...
-        UnboundLocalError: local variable 'x' referenced before assignment
-    
-    Make sure builtins are customizable.
-    
-        >>> t('$min(1, 2)')()
-        u'1\n'
-        >>> t('$min(1, 2)', builtins={})()
-        Traceback (most recent call last):
-            ...
-        NameError: global name 'min' is not defined
-        
-    Test vars.
-    
-        >>> x = t('$var x: 1')()
-        >>> x.x
-        u'1'
-        >>> x = t('$var x = 1')()
-        >>> x.x
-        1
-        >>> x = t('$var x:  \n    foo\n    bar')()
-        >>> x.x
-        u'foo\nbar\n'
-
-    Test BOM chars.
-
-        >>> t('\xef\xbb\xbf$def with(x)\n$x')('foo')
-        u'foo\n'
-
-    Test for with weird cases.
-
-        >>> t('$for i in range(10)[1:5]:\n    $i')()
-        u'1\n2\n3\n4\n'
-        >>> t("$for k, v in {'a': 1, 'b': 2}.items():\n    $k $v")()
-        u'a 1\nb 2\n'
-        >>> t("$for k, v in ({'a': 1, 'b': 2}.items():\n    $k $v")()
-        Traceback (most recent call last):
-            ...
-        SyntaxError: invalid syntax
-
-    Test datetime.
-
-        >>> import datetime
-        >>> t("$def with (date)\n$date.strftime('%m %Y')")(datetime.datetime(2009, 1, 1))
-        u'01 2009\n'
-    """
-    pass
-            
-if __name__ == "__main__":
-    import sys
-    if '--compile' in sys.argv:
-        compile_templates(sys.argv[2])
-    else:
-        import doctest
-        doctest.testmod()
--- a/bundled/webpy/web/test.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-"""test utilities
-(part of web.py)
-"""
-import unittest
-import sys, os
-import web
-
-TestCase = unittest.TestCase
-TestSuite = unittest.TestSuite
-
-def load_modules(names):
-    return [__import__(name, None, None, "x") for name in names]
-
-def module_suite(module, classnames=None):
-    """Makes a suite from a module."""
-    if classnames:
-        return unittest.TestLoader().loadTestsFromNames(classnames, module)
-    elif hasattr(module, 'suite'):
-        return module.suite()
-    else:
-        return unittest.TestLoader().loadTestsFromModule(module)
-
-def doctest_suite(module_names):
-    """Makes a test suite from doctests."""
-    import doctest
-    suite = TestSuite()
-    for mod in load_modules(module_names):
-        suite.addTest(doctest.DocTestSuite(mod))
-    return suite
-    
-def suite(module_names):
-    """Creates a suite from multiple modules."""
-    suite = TestSuite()
-    for mod in load_modules(module_names):
-        suite.addTest(module_suite(mod))
-    return suite
-
-def runTests(suite):
-    runner = unittest.TextTestRunner()
-    return runner.run(suite)
-
-def main(suite=None):
-    if not suite:
-        main_module = __import__('__main__')
-        # allow command line switches
-        args = [a for a in sys.argv[1:] if not a.startswith('-')]
-        suite = module_suite(main_module, args or None)
-
-    result = runTests(suite)
-    sys.exit(not result.wasSuccessful())
-
--- a/bundled/webpy/web/utils.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1112 +0,0 @@
-
-#!/usr/bin/env python
-"""
-General Utilities
-(part of web.py)
-"""
-
-__all__ = [
-  "Storage", "storage", "storify", 
-  "iters", 
-  "rstrips", "lstrips", "strips", 
-  "safeunicode", "safestr", "utf8",
-  "TimeoutError", "timelimit",
-  "Memoize", "memoize",
-  "re_compile", "re_subm",
-  "group", "uniq", "iterview",
-  "IterBetter", "iterbetter",
-  "dictreverse", "dictfind", "dictfindall", "dictincr", "dictadd",
-  "listget", "intget", "datestr",
-  "numify", "denumify", "commify", "dateify",
-  "nthstr",
-  "CaptureStdout", "capturestdout", "Profile", "profile",
-  "tryall",
-  "ThreadedDict", "threadeddict",
-  "autoassign",
-  "to36",
-  "safemarkdown",
-  "sendmail"
-]
-
-import re, sys, time, threading, itertools
-
-try:
-    import subprocess
-except ImportError: 
-    subprocess = None
-
-try: import datetime
-except ImportError: pass
-
-try: set
-except NameError:
-    from sets import Set as set
-
-class Storage(dict):
-    """
-    A Storage object is like a dictionary except `obj.foo` can be used
-    in addition to `obj['foo']`.
-    
-        >>> o = storage(a=1)
-        >>> o.a
-        1
-        >>> o['a']
-        1
-        >>> o.a = 2
-        >>> o['a']
-        2
-        >>> del o.a
-        >>> o.a
-        Traceback (most recent call last):
-            ...
-        AttributeError: 'a'
-    
-    """
-    def __getattr__(self, key): 
-        try:
-            return self[key]
-        except KeyError, k:
-            raise AttributeError, k
-    
-    def __setattr__(self, key, value): 
-        self[key] = value
-    
-    def __delattr__(self, key):
-        try:
-            del self[key]
-        except KeyError, k:
-            raise AttributeError, k
-    
-    def __repr__(self):     
-        return '<Storage ' + dict.__repr__(self) + '>'
-
-storage = Storage
-
-def storify(mapping, *requireds, **defaults):
-    """
-    Creates a `storage` object from dictionary `mapping`, raising `KeyError` if
-    d doesn't have all of the keys in `requireds` and using the default 
-    values for keys found in `defaults`.
-
-    For example, `storify({'a':1, 'c':3}, b=2, c=0)` will return the equivalent of
-    `storage({'a':1, 'b':2, 'c':3})`.
-    
-    If a `storify` value is a list (e.g. multiple values in a form submission), 
-    `storify` returns the last element of the list, unless the key appears in 
-    `defaults` as a list. Thus:
-    
-        >>> storify({'a':[1, 2]}).a
-        2
-        >>> storify({'a':[1, 2]}, a=[]).a
-        [1, 2]
-        >>> storify({'a':1}, a=[]).a
-        [1]
-        >>> storify({}, a=[]).a
-        []
-    
-    Similarly, if the value has a `value` attribute, `storify will return _its_
-    value, unless the key appears in `defaults` as a dictionary.
-    
-        >>> storify({'a':storage(value=1)}).a
-        1
-        >>> storify({'a':storage(value=1)}, a={}).a
-        <Storage {'value': 1}>
-        >>> storify({}, a={}).a
-        {}
-        
-    Optionally, keyword parameter `_unicode` can be passed to convert all values to unicode.
-    
-        >>> storify({'x': 'a'}, _unicode=True)
-        <Storage {'x': u'a'}>
-        >>> storify({'x': storage(value='a')}, x={}, _unicode=True)
-        <Storage {'x': <Storage {'value': 'a'}>}>
-        >>> storify({'x': storage(value='a')}, _unicode=True)
-        <Storage {'x': u'a'}>
-    """
-    _unicode = defaults.pop('_unicode', False)
-    def unicodify(s):
-        if _unicode and isinstance(s, str): return safeunicode(s)
-        else: return s
-        
-    def getvalue(x):
-        if hasattr(x, 'value'):
-            return unicodify(x.value)
-        else:
-            return unicodify(x)
-    
-    stor = Storage()
-    for key in requireds + tuple(mapping.keys()):
-        value = mapping[key]
-        if isinstance(value, list):
-            if isinstance(defaults.get(key), list):
-                value = [getvalue(x) for x in value]
-            else:
-                value = value[-1]
-        if not isinstance(defaults.get(key), dict):
-            value = getvalue(value)
-        if isinstance(defaults.get(key), list) and not isinstance(value, list):
-            value = [value]
-        setattr(stor, key, value)
-
-    for (key, value) in defaults.iteritems():
-        result = value
-        if hasattr(stor, key): 
-            result = stor[key]
-        if value == () and not isinstance(result, tuple): 
-            result = (result,)
-        setattr(stor, key, result)
-    
-    return stor
-
-iters = [list, tuple]
-import __builtin__
-if hasattr(__builtin__, 'set'):
-    iters.append(set)
-if hasattr(__builtin__, 'frozenset'):
-    iters.append(set)
-if sys.version_info < (2,6): # sets module deprecated in 2.6
-    try:
-        from sets import Set
-        iters.append(Set)
-    except ImportError: 
-        pass
-    
-class _hack(tuple): pass
-iters = _hack(iters)
-iters.__doc__ = """
-A list of iterable items (like lists, but not strings). Includes whichever
-of lists, tuples, sets, and Sets are available in this version of Python.
-"""
-
-def _strips(direction, text, remove):
-    if direction == 'l': 
-        if text.startswith(remove): 
-            return text[len(remove):]
-    elif direction == 'r':
-        if text.endswith(remove):   
-            return text[:-len(remove)]
-    else: 
-        raise ValueError, "Direction needs to be r or l."
-    return text
-
-def rstrips(text, remove):
-    """
-    removes the string `remove` from the right of `text`
-
-        >>> rstrips("foobar", "bar")
-        'foo'
-    
-    """
-    return _strips('r', text, remove)
-
-def lstrips(text, remove):
-    """
-    removes the string `remove` from the left of `text`
-    
-        >>> lstrips("foobar", "foo")
-        'bar'
-    
-    """
-    return _strips('l', text, remove)
-
-def strips(text, remove):
-    """
-    removes the string `remove` from the both sides of `text`
-
-        >>> strips("foobarfoo", "foo")
-        'bar'
-    
-    """
-    return rstrips(lstrips(text, remove), remove)
-
-def safeunicode(obj, encoding='utf-8'):
-    r"""
-    Converts any given object to unicode string.
-    
-        >>> safeunicode('hello')
-        u'hello'
-        >>> safeunicode(2)
-        u'2'
-        >>> safeunicode('\xe1\x88\xb4')
-        u'\u1234'
-    """
-    if isinstance(obj, unicode):
-        return obj
-    elif isinstance(obj, str):
-        return obj.decode(encoding)
-    else:
-        if hasattr(obj, '__unicode__'):
-            return unicode(obj)
-        else:
-            return str(obj).decode(encoding)
-    
-def safestr(obj, encoding='utf-8'):
-    r"""
-    Converts any given object to utf-8 encoded string. 
-    
-        >>> safestr('hello')
-        'hello'
-        >>> safestr(u'\u1234')
-        '\xe1\x88\xb4'
-        >>> safestr(2)
-        '2'
-    """
-    if isinstance(obj, unicode):
-        return obj.encode('utf-8')
-    elif isinstance(obj, str):
-        return obj
-    elif hasattr(obj, 'next') and hasattr(obj, '__iter__'): # iterator
-        return itertools.imap(safestr, obj)
-    else:
-        return str(obj)
-
-# for backward-compatibility
-utf8 = safestr
-    
-class TimeoutError(Exception): pass
-def timelimit(timeout):
-    """
-    A decorator to limit a function to `timeout` seconds, raising `TimeoutError`
-    if it takes longer.
-    
-        >>> import time
-        >>> def meaningoflife():
-        ...     time.sleep(.2)
-        ...     return 42
-        >>> 
-        >>> timelimit(.1)(meaningoflife)()
-        Traceback (most recent call last):
-            ...
-        TimeoutError: took too long
-        >>> timelimit(1)(meaningoflife)()
-        42
-
-    _Caveat:_ The function isn't stopped after `timeout` seconds but continues 
-    executing in a separate thread. (There seems to be no way to kill a thread.)
-
-    inspired by <http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/473878>
-    """
-    def _1(function):
-        def _2(*args, **kw):
-            class Dispatch(threading.Thread):
-                def __init__(self):
-                    threading.Thread.__init__(self)
-                    self.result = None
-                    self.error = None
-
-                    self.setDaemon(True)
-                    self.start()
-
-                def run(self):
-                    try:
-                        self.result = function(*args, **kw)
-                    except:
-                        self.error = sys.exc_info()
-
-            c = Dispatch()
-            c.join(timeout)
-            if c.isAlive():
-                raise TimeoutError, 'took too long'
-            if c.error:
-                raise c.error[0], c.error[1]
-            return c.result
-        return _2
-    return _1
-
-class Memoize:
-    """
-    'Memoizes' a function, caching its return values for each input.
-    
-        >>> import time
-        >>> def meaningoflife():
-        ...     time.sleep(.2)
-        ...     return 42
-        >>> fastlife = memoize(meaningoflife)
-        >>> meaningoflife()
-        42
-        >>> timelimit(.1)(meaningoflife)()
-        Traceback (most recent call last):
-            ...
-        TimeoutError: took too long
-        >>> fastlife()
-        42
-        >>> timelimit(.1)(fastlife)()
-        42
-    
-    """
-    def __init__(self, func): 
-        self.func = func
-        self.cache = {}
-    def __call__(self, *args, **keywords):
-        key = (args, tuple(keywords.items()))
-        if key not in self.cache: 
-            self.cache[key] = self.func(*args, **keywords)
-        return self.cache[key]
-
-memoize = Memoize
-
-re_compile = memoize(re.compile) #@@ threadsafe?
-re_compile.__doc__ = """
-A memoized version of re.compile.
-"""
-
-class _re_subm_proxy:
-    def __init__(self): 
-        self.match = None
-    def __call__(self, match): 
-        self.match = match
-        return ''
-
-def re_subm(pat, repl, string):
-    """
-    Like re.sub, but returns the replacement _and_ the match object.
-    
-        >>> t, m = re_subm('g(oo+)fball', r'f\\1lish', 'goooooofball')
-        >>> t
-        'foooooolish'
-        >>> m.groups()
-        ('oooooo',)
-    """
-    compiled_pat = re_compile(pat)
-    proxy = _re_subm_proxy()
-    compiled_pat.sub(proxy.__call__, string)
-    return compiled_pat.sub(repl, string), proxy.match
-
-def group(seq, size): 
-    """
-    Returns an iterator over a series of lists of length size from iterable.
-
-        >>> list(group([1,2,3,4], 2))
-        [[1, 2], [3, 4]]
-    """
-    if not hasattr(seq, 'next'):  
-        seq = iter(seq)
-    while True: 
-        yield [seq.next() for i in xrange(size)]
-
-def uniq(seq):
-   """
-   Removes duplicate elements from a list.
-
-       >>> uniq([1,2,3,1,4,5,6])
-       [1, 2, 3, 4, 5, 6]
-   """
-   seen = set()
-   result = []
-   for item in seq:
-       if item in seen: continue
-       seen.add(item)
-       result.append(item)
-   return result
-
-def iterview(x):
-   """
-   Takes an iterable `x` and returns an iterator over it
-   which prints its progress to stderr as it iterates through.
-   """
-   WIDTH = 70
-
-   def plainformat(n, lenx):
-       return '%5.1f%% (%*d/%d)' % ((float(n)/lenx)*100, len(str(lenx)), n, lenx)
-
-   def bars(size, n, lenx):
-       val = int((float(n)*size)/lenx + 0.5)
-       if size - val:
-           spacing = ">" + (" "*(size-val))[1:]
-       else:
-           spacing = ""
-       return "[%s%s]" % ("="*val, spacing)
-
-   def eta(elapsed, n, lenx):
-       if n == 0:
-           return '--:--:--'
-       if n == lenx:
-           secs = int(elapsed)
-       else:
-           secs = int((elapsed/n) * (lenx-n))
-       mins, secs = divmod(secs, 60)
-       hrs, mins = divmod(mins, 60)
-
-       return '%02d:%02d:%02d' % (hrs, mins, secs)
-
-   def format(starttime, n, lenx):
-       out = plainformat(n, lenx) + ' '
-       if n == lenx:
-           end = '     '
-       else:
-           end = ' ETA '
-       end += eta(time.time() - starttime, n, lenx)
-       out += bars(WIDTH - len(out) - len(end), n, lenx)
-       out += end
-       return out
-
-   starttime = time.time()
-   lenx = len(x)
-   for n, y in enumerate(x):
-       sys.stderr.write('\r' + format(starttime, n, lenx))
-       yield y
-   sys.stderr.write('\r' + format(starttime, n+1, lenx) + '\n')
-
-class IterBetter:
-    """
-    Returns an object that can be used as an iterator 
-    but can also be used via __getitem__ (although it 
-    cannot go backwards -- that is, you cannot request 
-    `iterbetter[0]` after requesting `iterbetter[1]`).
-    
-        >>> import itertools
-        >>> c = iterbetter(itertools.count())
-        >>> c[1]
-        1
-        >>> c[5]
-        5
-        >>> c[3]
-        Traceback (most recent call last):
-            ...
-        IndexError: already passed 3
-    """
-    def __init__(self, iterator): 
-        self.i, self.c = iterator, 0
-    def __iter__(self): 
-        while 1:    
-            yield self.i.next()
-            self.c += 1
-    def __getitem__(self, i):
-        #todo: slices
-        if i < self.c: 
-            raise IndexError, "already passed "+str(i)
-        try:
-            while i > self.c: 
-                self.i.next()
-                self.c += 1
-            # now self.c == i
-            self.c += 1
-            return self.i.next()
-        except StopIteration: 
-            raise IndexError, str(i)
-iterbetter = IterBetter
-
-def dictreverse(mapping):
-    """
-    Returns a new dictionary with keys and values swapped.
-    
-        >>> dictreverse({1: 2, 3: 4})
-        {2: 1, 4: 3}
-    """
-    return dict([(value, key) for (key, value) in mapping.iteritems()])
-
-def dictfind(dictionary, element):
-    """
-    Returns a key whose value in `dictionary` is `element` 
-    or, if none exists, None.
-    
-        >>> d = {1:2, 3:4}
-        >>> dictfind(d, 4)
-        3
-        >>> dictfind(d, 5)
-    """
-    for (key, value) in dictionary.iteritems():
-        if element is value: 
-            return key
-
-def dictfindall(dictionary, element):
-    """
-    Returns the keys whose values in `dictionary` are `element`
-    or, if none exists, [].
-    
-        >>> d = {1:4, 3:4}
-        >>> dictfindall(d, 4)
-        [1, 3]
-        >>> dictfindall(d, 5)
-        []
-    """
-    res = []
-    for (key, value) in dictionary.iteritems():
-        if element is value:
-            res.append(key)
-    return res
-
-def dictincr(dictionary, element):
-    """
-    Increments `element` in `dictionary`, 
-    setting it to one if it doesn't exist.
-    
-        >>> d = {1:2, 3:4}
-        >>> dictincr(d, 1)
-        3
-        >>> d[1]
-        3
-        >>> dictincr(d, 5)
-        1
-        >>> d[5]
-        1
-    """
-    dictionary.setdefault(element, 0)
-    dictionary[element] += 1
-    return dictionary[element]
-
-def dictadd(*dicts):
-    """
-    Returns a dictionary consisting of the keys in the argument dictionaries.
-    If they share a key, the value from the last argument is used.
-    
-        >>> dictadd({1: 0, 2: 0}, {2: 1, 3: 1})
-        {1: 0, 2: 1, 3: 1}
-    """
-    result = {}
-    for dct in dicts:
-        result.update(dct)
-    return result
-
-def listget(lst, ind, default=None):
-    """
-    Returns `lst[ind]` if it exists, `default` otherwise.
-    
-        >>> listget(['a'], 0)
-        'a'
-        >>> listget(['a'], 1)
-        >>> listget(['a'], 1, 'b')
-        'b'
-    """
-    if len(lst)-1 < ind: 
-        return default
-    return lst[ind]
-
-def intget(integer, default=None):
-    """
-    Returns `integer` as an int or `default` if it can't.
-    
-        >>> intget('3')
-        3
-        >>> intget('3a')
-        >>> intget('3a', 0)
-        0
-    """
-    try:
-        return int(integer)
-    except (TypeError, ValueError):
-        return default
-
-def datestr(then, now=None):
-    """
-    Converts a (UTC) datetime object to a nice string representation.
-    
-        >>> from datetime import datetime, timedelta
-        >>> d = datetime(1970, 5, 1)
-        >>> datestr(d, now=d)
-        '0 microseconds ago'
-        >>> for t, v in {
-        ...   timedelta(microseconds=1): '1 microsecond ago',
-        ...   timedelta(microseconds=2): '2 microseconds ago',
-        ...   -timedelta(microseconds=1): '1 microsecond from now',
-        ...   -timedelta(microseconds=2): '2 microseconds from now',
-        ...   timedelta(microseconds=2000): '2 milliseconds ago',
-        ...   timedelta(seconds=2): '2 seconds ago',
-        ...   timedelta(seconds=2*60): '2 minutes ago',
-        ...   timedelta(seconds=2*60*60): '2 hours ago',
-        ...   timedelta(days=2): '2 days ago',
-        ... }.iteritems():
-        ...     assert datestr(d, now=d+t) == v
-        >>> datestr(datetime(1970, 1, 1), now=d)
-        'January  1'
-        >>> datestr(datetime(1969, 1, 1), now=d)
-        'January  1, 1969'
-        >>> datestr(datetime(1970, 6, 1), now=d)
-        'June  1, 1970'
-        >>> datestr(None)
-        ''
-    """
-    def agohence(n, what, divisor=None):
-        if divisor: n = n // divisor
-
-        out = str(abs(n)) + ' ' + what       # '2 day'
-        if abs(n) != 1: out += 's'           # '2 days'
-        out += ' '                           # '2 days '
-        if n < 0:
-            out += 'from now'
-        else:
-            out += 'ago'
-        return out                           # '2 days ago'
-
-    oneday = 24 * 60 * 60
-
-    if not then: return ""
-    if not now: now = datetime.datetime.utcnow()
-    if type(now).__name__ == "DateTime":
-        now = datetime.datetime.fromtimestamp(now)
-    if type(then).__name__ == "DateTime":
-        then = datetime.datetime.fromtimestamp(then)
-    elif type(then).__name__ == "date":
-        then = datetime.datetime(then.year, then.month, then.day)
-
-    delta = now - then
-    deltaseconds = int(delta.days * oneday + delta.seconds + delta.microseconds * 1e-06)
-    deltadays = abs(deltaseconds) // oneday
-    if deltaseconds < 0: deltadays *= -1 # fix for oddity of floor
-
-    if deltadays:
-        if abs(deltadays) < 4:
-            return agohence(deltadays, 'day')
-
-        out = then.strftime('%B %e') # e.g. 'June 13'
-        if then.year != now.year or deltadays < 0:
-            out += ', %s' % then.year
-        return out
-
-    if int(deltaseconds):
-        if abs(deltaseconds) > (60 * 60):
-            return agohence(deltaseconds, 'hour', 60 * 60)
-        elif abs(deltaseconds) > 60:
-            return agohence(deltaseconds, 'minute', 60)
-        else:
-            return agohence(deltaseconds, 'second')
-
-    deltamicroseconds = delta.microseconds
-    if delta.days: deltamicroseconds = int(delta.microseconds - 1e6) # datetime oddity
-    if abs(deltamicroseconds) > 1000:
-        return agohence(deltamicroseconds, 'millisecond', 1000)
-
-    return agohence(deltamicroseconds, 'microsecond')
-
-def numify(string):
-    """
-    Removes all non-digit characters from `string`.
-    
-        >>> numify('800-555-1212')
-        '8005551212'
-        >>> numify('800.555.1212')
-        '8005551212'
-    
-    """
-    return ''.join([c for c in str(string) if c.isdigit()])
-
-def denumify(string, pattern):
-    """
-    Formats `string` according to `pattern`, where the letter X gets replaced
-    by characters from `string`.
-    
-        >>> denumify("8005551212", "(XXX) XXX-XXXX")
-        '(800) 555-1212'
-    
-    """
-    out = []
-    for c in pattern:
-        if c == "X":
-            out.append(string[0])
-            string = string[1:]
-        else:
-            out.append(c)
-    return ''.join(out)
-
-def commify(n):
-    """
-    Add commas to an integer `n`.
-
-        >>> commify(1)
-        '1'
-        >>> commify(123)
-        '123'
-        >>> commify(1234)
-        '1,234'
-        >>> commify(1234567890)
-        '1,234,567,890'
-        >>> commify(123.0)
-        '123.0'
-        >>> commify(1234.5)
-        '1,234.5'
-        >>> commify(1234.56789)
-        '1,234.56789'
-        >>> commify('%.2f' % 1234.5)
-        '1,234.50'
-        >>> commify(None)
-        >>>
-
-    """
-    if n is None: return None
-    n = str(n)
-    if '.' in n:
-        dollars, cents = n.split('.')
-    else:
-        dollars, cents = n, None
-
-    r = []
-    for i, c in enumerate(str(dollars)[::-1]):
-        if i and (not (i % 3)):
-            r.insert(0, ',')
-        r.insert(0, c)
-    out = ''.join(r)
-    if cents:
-        out += '.' + cents
-    return out
-
-def dateify(datestring):
-    """
-    Formats a numified `datestring` properly.
-    """
-    return denumify(datestring, "XXXX-XX-XX XX:XX:XX")
-
-
-def nthstr(n):
-    """
-    Formats an ordinal.
-    Doesn't handle negative numbers.
-
-        >>> nthstr(1)
-        '1st'
-        >>> nthstr(0)
-        '0th'
-        >>> [nthstr(x) for x in [2, 3, 4, 5, 10, 11, 12, 13, 14, 15]]
-        ['2nd', '3rd', '4th', '5th', '10th', '11th', '12th', '13th', '14th', '15th']
-        >>> [nthstr(x) for x in [91, 92, 93, 94, 99, 100, 101, 102]]
-        ['91st', '92nd', '93rd', '94th', '99th', '100th', '101st', '102nd']
-        >>> [nthstr(x) for x in [111, 112, 113, 114, 115]]
-        ['111th', '112th', '113th', '114th', '115th']
-
-    """
-    
-    assert n >= 0
-    if n % 100 in [11, 12, 13]: return '%sth' % n
-    return {1: '%sst', 2: '%snd', 3: '%srd'}.get(n % 10, '%sth') % n
-
-def cond(predicate, consequence, alternative=None):
-    """
-    Function replacement for if-else to use in expressions.
-        
-        >>> x = 2
-        >>> cond(x % 2 == 0, "even", "odd")
-        'even'
-        >>> cond(x % 2 == 0, "even", "odd") + '_row'
-        'even_row'
-    """
-    if predicate:
-        return consequence
-    else:
-        return alternative
-
-class CaptureStdout:
-    """
-    Captures everything `func` prints to stdout and returns it instead.
-    
-        >>> def idiot():
-        ...     print "foo"
-        >>> capturestdout(idiot)()
-        'foo\\n'
-    
-    **WARNING:** Not threadsafe!
-    """
-    def __init__(self, func): 
-        self.func = func
-    def __call__(self, *args, **keywords):
-        from cStringIO import StringIO
-        # Not threadsafe!
-        out = StringIO()
-        oldstdout = sys.stdout
-        sys.stdout = out
-        try: 
-            self.func(*args, **keywords)
-        finally: 
-            sys.stdout = oldstdout
-        return out.getvalue()
-
-capturestdout = CaptureStdout
-
-class Profile:
-    """
-    Profiles `func` and returns a tuple containing its output
-    and a string with human-readable profiling information.
-        
-        >>> import time
-        >>> out, inf = profile(time.sleep)(.001)
-        >>> out
-        >>> inf[:10].strip()
-        'took 0.0'
-    """
-    def __init__(self, func): 
-        self.func = func
-    def __call__(self, *args): ##, **kw):   kw unused
-        import hotshot, hotshot.stats, tempfile ##, time already imported
-        temp = tempfile.NamedTemporaryFile()
-        prof = hotshot.Profile(temp.name)
-
-        stime = time.time()
-        result = prof.runcall(self.func, *args)
-        stime = time.time() - stime
-        prof.close()
-
-        import cStringIO
-        out = cStringIO.StringIO()
-        stats = hotshot.stats.load(temp.name)
-        stats.stream = out
-        stats.strip_dirs()
-        stats.sort_stats('time', 'calls')
-        stats.print_stats(40)
-        stats.print_callers()
-
-        x =  '\n\ntook '+ str(stime) + ' seconds\n'
-        x += out.getvalue()
-
-        return result, x
-
-profile = Profile
-
-
-import traceback
-# hack for compatibility with Python 2.3:
-if not hasattr(traceback, 'format_exc'):
-    from cStringIO import StringIO
-    def format_exc(limit=None):
-        strbuf = StringIO()
-        traceback.print_exc(limit, strbuf)
-        return strbuf.getvalue()
-    traceback.format_exc = format_exc
-
-def tryall(context, prefix=None):
-    """
-    Tries a series of functions and prints their results. 
-    `context` is a dictionary mapping names to values; 
-    the value will only be tried if it's callable.
-    
-        >>> tryall(dict(j=lambda: True))
-        j: True
-        ----------------------------------------
-        results:
-           True: 1
-
-    For example, you might have a file `test/stuff.py` 
-    with a series of functions testing various things in it. 
-    At the bottom, have a line:
-
-        if __name__ == "__main__": tryall(globals())
-
-    Then you can run `python test/stuff.py` and get the results of 
-    all the tests.
-    """
-    context = context.copy() # vars() would update
-    results = {}
-    for (key, value) in context.iteritems():
-        if not hasattr(value, '__call__'): 
-            continue
-        if prefix and not key.startswith(prefix): 
-            continue
-        print key + ':',
-        try:
-            r = value()
-            dictincr(results, r)
-            print r
-        except:
-            print 'ERROR'
-            dictincr(results, 'ERROR')
-            print '   ' + '\n   '.join(traceback.format_exc().split('\n'))
-        
-    print '-'*40
-    print 'results:'
-    for (key, value) in results.iteritems():
-        print ' '*2, str(key)+':', value
-        
-class ThreadedDict:
-    """
-    Thread local storage.
-    
-        >>> d = ThreadedDict()
-        >>> d.x = 1
-        >>> d.x
-        1
-        >>> import threading
-        >>> def f(): d.x = 2
-        ...
-        >>> t = threading.Thread(target=f)
-        >>> t.start()
-        >>> t.join()
-        >>> d.x
-        1
-    """
-    def __getattr__(self, key):
-        return getattr(self._getd(), key)
-
-    def __setattr__(self, key, value):
-        return setattr(self._getd(), key, value)
-
-    def __delattr__(self, key):
-        return delattr(self._getd(), key)
-
-    def __hash__(self): 
-        return id(self)
-
-    def _getd(self):
-        t = threading.currentThread()
-        if not hasattr(t, '_d'):
-            # using __dict__ of thread as thread local storage
-            t._d = {}
-
-        # there could be multiple instances of ThreadedDict.
-        # use self as key
-        if self not in t._d:
-            t._d[self] = storage()
-        return t._d[self]
-
-threadeddict = ThreadedDict
-
-def autoassign(self, locals):
-    """
-    Automatically assigns local variables to `self`.
-    
-        >>> self = storage()
-        >>> autoassign(self, dict(a=1, b=2))
-        >>> self
-        <Storage {'a': 1, 'b': 2}>
-    
-    Generally used in `__init__` methods, as in:
-
-        def __init__(self, foo, bar, baz=1): autoassign(self, locals())
-    """
-    for (key, value) in locals.iteritems():
-        if key == 'self': 
-            continue
-        setattr(self, key, value)
-
-def to36(q):
-    """
-    Converts an integer to base 36 (a useful scheme for human-sayable IDs).
-    
-        >>> to36(35)
-        'z'
-        >>> to36(119292)
-        '2k1o'
-        >>> int(to36(939387374), 36)
-        939387374
-        >>> to36(0)
-        '0'
-        >>> to36(-393)
-        Traceback (most recent call last):
-            ... 
-        ValueError: must supply a positive integer
-    
-    """
-    if q < 0: raise ValueError, "must supply a positive integer"
-    letters = "0123456789abcdefghijklmnopqrstuvwxyz"
-    converted = []
-    while q != 0:
-        q, r = divmod(q, 36)
-        converted.insert(0, letters[r])
-    return "".join(converted) or '0'
-
-
-r_url = re_compile('(?<!\()(http://(\S+))')
-def safemarkdown(text):
-    """
-    Converts text to HTML following the rules of Markdown, but blocking any
-    outside HTML input, so that only the things supported by Markdown
-    can be used. Also converts raw URLs to links.
-
-    (requires [markdown.py](http://webpy.org/markdown.py))
-    """
-    from markdown import markdown
-    if text:
-        text = text.replace('<', '&lt;')
-        # TODO: automatically get page title?
-        text = r_url.sub(r'<\1>', text)
-        text = markdown(text)
-        return text
-
-def sendmail(from_address, to_address, subject, message, headers=None, **kw):
-    """
-    Sends the email message `message` with mail and envelope headers
-    for from `from_address_` to `to_address` with `subject`. 
-    Additional email headers can be specified with the dictionary 
-    `headers.
-
-    If `web.config.smtp_server` is set, it will send the message
-    to that SMTP server. Otherwise it will look for 
-    `/usr/sbin/sendmail`, the typical location for the sendmail-style
-    binary. To use sendmail from a different path, set `web.config.sendmail_path`.
-    """
-    try:
-        import webapi
-    except ImportError:
-        webapi = Storage(config=Storage())
-    
-    if headers is None: headers = {}
-    
-    cc = kw.get('cc', [])
-    bcc = kw.get('bcc', [])
-    
-    def listify(x):
-        if not isinstance(x, list):
-            return [safestr(x)]
-        else:
-            return [safestr(a) for a in x]
-
-    from_address = safestr(from_address)
-
-    to_address = listify(to_address)
-    cc = listify(cc)
-    bcc = listify(bcc)
-
-    recipients = to_address + cc + bcc
-    
-    headers = dictadd({
-      'MIME-Version': '1.0',
-      'Content-Type': 'text/plain; charset=UTF-8',
-      'Content-Disposition': 'inline',
-      'From': from_address,
-      'To': ", ".join(to_address),
-      'Subject': subject
-    }, headers)
-
-    if cc:
-        headers['Cc'] = ", ".join(cc)
-    
-    import email.Utils
-    from_address = email.Utils.parseaddr(from_address)[1]
-    recipients = [email.Utils.parseaddr(r)[1] for r in recipients]
-    message = ('\n'.join([safestr('%s: %s' % x) for x in headers.iteritems()])
-      + "\n\n" +  safestr(message))
-
-    if webapi.config.get('smtp_server'):
-        server = webapi.config.get('smtp_server')
-        port = webapi.config.get('smtp_port', 0)
-        username = webapi.config.get('smtp_username') 
-        password = webapi.config.get('smtp_password')
-        debug_level = webapi.config.get('smtp_debuglevel', None)
-        starttls = webapi.config.get('smtp_starttls', False)
-
-        import smtplib
-        smtpserver = smtplib.SMTP(server, port)
-
-        if debug_level:
-            smtpserver.set_debuglevel(debug_level)
-
-        if starttls:
-            smtpserver.ehlo()
-            smtpserver.starttls()
-            smtpserver.ehlo()
-
-        if username and password:
-            smtpserver.login(username, password)
-
-        smtpserver.sendmail(from_address, recipients, message)
-        smtpserver.quit()
-    else:
-        sendmail = webapi.config.get('sendmail_path', '/usr/sbin/sendmail')
-        
-        assert not from_address.startswith('-'), 'security'
-        for r in recipients:
-            assert not r.startswith('-'), 'security'
-                
-
-        if subprocess:
-            p = subprocess.Popen(['/usr/sbin/sendmail', '-f', from_address] + recipients, stdin=subprocess.PIPE)
-            p.stdin.write(message)
-            p.stdin.close()
-            p.wait()
-        else:
-            import os
-            i, o = os.popen2(["/usr/lib/sendmail", '-f', from_address] + recipients)
-            i.write(message)
-            i.close()
-            o.close()
-            del i, o
-
-if __name__ == "__main__":
-    import doctest
-    doctest.testmod()
--- a/bundled/webpy/web/webapi.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,368 +0,0 @@
-"""
-Web API (wrapper around WSGI)
-(from web.py)
-"""
-
-__all__ = [
-    "config",
-    "header", "debug",
-    "input", "data",
-    "setcookie", "cookies",
-    "ctx", 
-    "HTTPError", 
-
-    # 200, 201, 202
-    "OK", "Created", "Accepted",    
-    "ok", "created", "accepted",
-    
-    # 301, 302, 303, 304, 407
-    "Redirect", "Found", "SeeOther", "NotModified", "TempRedirect", 
-    "redirect", "found", "seeother", "notmodified", "tempredirect",
-
-    # 400, 401, 403, 404, 405, 406, 409, 410, 412
-    "BadRequest", "Unauthorized", "Forbidden", "NoMethod", "NotFound", "NotAcceptable", "Conflict", "Gone", "PreconditionFailed",
-    "badrequest", "unauthorized", "forbidden", "nomethod", "notfound", "notacceptable", "conflict", "gone", "preconditionfailed",
-
-    # 500
-    "InternalError", 
-    "internalerror",
-]
-
-import sys, cgi, Cookie, pprint, urlparse, urllib
-from utils import storage, storify, threadeddict, dictadd, intget, utf8
-
-config = storage()
-config.__doc__ = """
-A configuration object for various aspects of web.py.
-
-`debug`
-   : when True, enables reloading, disabled template caching and sets internalerror to debugerror.
-"""
-
-class HTTPError(Exception):
-    def __init__(self, status, headers={}, data=""):
-        ctx.status = status
-        for k, v in headers.items():
-            header(k, v)
-        self.data = data
-        Exception.__init__(self, status)
-        
-def _status_code(status, data=None, classname=None, docstring=None):
-    if data is None:
-        data = status.split(" ", 1)[1]
-    classname = status.split(" ", 1)[1].replace(' ', '') # 304 Not Modified -> NotModified    
-    docstring = docstring or '`%s` status' % status
-
-    def __init__(self, data=data, headers={}):
-        HTTPError.__init__(self, status, headers, data)
-        
-    # trick to create class dynamically with dynamic docstring.
-    return type(classname, (HTTPError, object), {
-        '__doc__': docstring,
-        '__init__': __init__
-    })
-
-ok = OK = _status_code("200 OK", data="")
-created = Created = _status_code("201 Created")
-accepted = Accepted = _status_code("202 Accepted")
-
-class Redirect(HTTPError):
-    """A `301 Moved Permanently` redirect."""
-    def __init__(self, url, status='301 Moved Permanently', absolute=False):
-        """
-        Returns a `status` redirect to the new URL. 
-        `url` is joined with the base URL so that things like 
-        `redirect("about") will work properly.
-        """
-        newloc = urlparse.urljoin(ctx.path, url)
-
-        if newloc.startswith('/'):
-            if absolute:
-                home = ctx.realhome
-            else:
-                home = ctx.home
-            newloc = home + newloc
-
-        headers = {
-            'Content-Type': 'text/html',
-            'Location': newloc
-        }
-        HTTPError.__init__(self, status, headers, "")
-
-redirect = Redirect
-
-class Found(Redirect):
-    """A `302 Found` redirect."""
-    def __init__(self, url, absolute=False):
-        Redirect.__init__(self, url, '302 Found', absolute=absolute)
-
-found = Found
-
-class SeeOther(Redirect):
-    """A `303 See Other` redirect."""
-    def __init__(self, url, absolute=False):
-        Redirect.__init__(self, url, '303 See Other', absolute=absolute)
-    
-seeother = SeeOther
-
-class NotModified(HTTPError):
-    """A `304 Not Modified` status."""
-    def __init__(self):
-        HTTPError.__init__(self, "304 Not Modified")
-
-notmodified = NotModified
-
-class TempRedirect(Redirect):
-    """A `307 Temporary Redirect` redirect."""
-    def __init__(self, url, absolute=False):
-        Redirect.__init__(self, url, '307 Temporary Redirect', absolute=absolute)
-
-tempredirect = TempRedirect
-
-class BadRequest(HTTPError):
-    """`400 Bad Request` error."""
-    message = "bad request"
-    def __init__(self):
-        status = "400 Bad Request"
-        headers = {'Content-Type': 'text/html'}
-        HTTPError.__init__(self, status, headers, self.message)
-
-badrequest = BadRequest
-
-class _NotFound(HTTPError):
-    """`404 Not Found` error."""
-    message = "not found"
-    def __init__(self, message=None):
-        status = '404 Not Found'
-        headers = {'Content-Type': 'text/html'}
-        HTTPError.__init__(self, status, headers, message or self.message)
-
-def NotFound(message=None):
-    """Returns HTTPError with '404 Not Found' error from the active application.
-    """
-    if message:
-        return _NotFound(message)
-    elif ctx.get('app_stack'):
-        return ctx.app_stack[-1].notfound()
-    else:
-        return _NotFound()
-
-notfound = NotFound
-
-unauthorized = Unauthorized = _status_code("401 Unauthorized")
-forbidden = Forbidden = _status_code("403 Forbidden")
-notacceptable = NotAcceptable = _status_code("406 Not Acceptable")
-conflict = Conflict = _status_code("409 Conflict")
-preconditionfailed = PreconditionFailed = _status_code("412 Precondition Failed")
-
-class NoMethod(HTTPError):
-    """A `405 Method Not Allowed` error."""
-    def __init__(self, cls=None):
-        status = '405 Method Not Allowed'
-        headers = {}
-        headers['Content-Type'] = 'text/html'
-        
-        methods = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE']
-        if cls:
-            methods = [method for method in methods if hasattr(cls, method)]
-
-        headers['Allow'] = ', '.join(methods)
-        data = None
-        HTTPError.__init__(self, status, headers, data)
-        
-nomethod = NoMethod
-
-class Gone(HTTPError):
-    """`410 Gone` error."""
-    message = "gone"
-    def __init__(self):
-        status = '410 Gone'
-        headers = {'Content-Type': 'text/html'}
-        HTTPError.__init__(self, status, headers, self.message)
-
-gone = Gone
-
-class _InternalError(HTTPError):
-    """500 Internal Server Error`."""
-    message = "internal server error"
-    
-    def __init__(self, message=None):
-        status = '500 Internal Server Error'
-        headers = {'Content-Type': 'text/html'}
-        HTTPError.__init__(self, status, headers, message or self.message)
-
-def InternalError(message=None):
-    """Returns HTTPError with '500 internal error' error from the active application.
-    """
-    if message:
-        return _InternalError(message)
-    elif ctx.get('app_stack'):
-        return ctx.app_stack[-1].internalerror()
-    else:
-        return _InternalError()
-
-internalerror = InternalError
-
-def header(hdr, value, unique=False):
-    """
-    Adds the header `hdr: value` with the response.
-    
-    If `unique` is True and a header with that name already exists,
-    it doesn't add a new one. 
-    """
-    hdr, value = utf8(hdr), utf8(value)
-    # protection against HTTP response splitting attack
-    if '\n' in hdr or '\r' in hdr or '\n' in value or '\r' in value:
-        raise ValueError, 'invalid characters in header'
-        
-    if unique is True:
-        for h, v in ctx.headers:
-            if h.lower() == hdr.lower(): return
-    
-    ctx.headers.append((hdr, value))
-
-def input(*requireds, **defaults):
-    """
-    Returns a `storage` object with the GET and POST arguments. 
-    See `storify` for how `requireds` and `defaults` work.
-    """
-    from cStringIO import StringIO
-    def dictify(fs): 
-        # hack to make web.input work with enctype='text/plain.
-        if fs.list is None:
-            fs.list = [] 
-
-        return dict([(k, fs[k]) for k in fs.keys()])
-    
-    _method = defaults.pop('_method', 'both')
-    
-    e = ctx.env.copy()
-    a = b = {}
-    
-    if _method.lower() in ['both', 'post', 'put']:
-        if e['REQUEST_METHOD'] in ['POST', 'PUT']:
-            if e.get('CONTENT_TYPE', '').lower().startswith('multipart/'):
-                # since wsgi.input is directly passed to cgi.FieldStorage, 
-                # it can not be called multiple times. Saving the FieldStorage
-                # object in ctx to allow calling web.input multiple times.
-                a = ctx.get('_fieldstorage')
-                if not a:
-                    fp = e['wsgi.input']
-                    a = cgi.FieldStorage(fp=fp, environ=e, keep_blank_values=1)
-                    ctx._fieldstorage = a
-            else:
-                fp = StringIO(data())
-                a = cgi.FieldStorage(fp=fp, environ=e, keep_blank_values=1)
-            a = dictify(a)
-
-    if _method.lower() in ['both', 'get']:
-        e['REQUEST_METHOD'] = 'GET'
-        b = dictify(cgi.FieldStorage(environ=e, keep_blank_values=1))
-
-    out = dictadd(b, a)
-    try:
-        defaults.setdefault('_unicode', True) # force unicode conversion by default.
-        return storify(out, *requireds, **defaults)
-    except KeyError:
-        raise badrequest()
-
-def data():
-    """Returns the data sent with the request."""
-    if 'data' not in ctx:
-        cl = intget(ctx.env.get('CONTENT_LENGTH'), 0)
-        ctx.data = ctx.env['wsgi.input'].read(cl)
-    return ctx.data
-
-def setcookie(name, value, expires="", domain=None, secure=False):
-    """Sets a cookie."""
-    if expires < 0: 
-        expires = -1000000000 
-    kargs = {'expires': expires, 'path':'/'}
-    if domain: 
-        kargs['domain'] = domain
-    if secure:
-        kargs['secure'] = secure
-    # @@ should we limit cookies to a different path?
-    cookie = Cookie.SimpleCookie()
-    cookie[name] = urllib.quote(utf8(value))
-    for key, val in kargs.iteritems(): 
-        cookie[name][key] = val
-    header('Set-Cookie', cookie.items()[0][1].OutputString())
-
-def cookies(*requireds, **defaults):
-    """
-    Returns a `storage` object with all the cookies in it.
-    See `storify` for how `requireds` and `defaults` work.
-    """
-    cookie = Cookie.SimpleCookie()
-    cookie.load(ctx.env.get('HTTP_COOKIE', ''))
-    try:
-        d = storify(cookie, *requireds, **defaults)
-        for k, v in d.items():
-            d[k] = v and urllib.unquote(v)
-        return d
-    except KeyError:
-        badrequest()
-        raise StopIteration
-
-def debug(*args):
-    """
-    Prints a prettyprinted version of `args` to stderr.
-    """
-    try: 
-        out = ctx.environ['wsgi.errors']
-    except: 
-        out = sys.stderr
-    for arg in args:
-        print >> out, pprint.pformat(arg)
-    return ''
-
-def _debugwrite(x):
-    try: 
-        out = ctx.environ['wsgi.errors']
-    except: 
-        out = sys.stderr
-    out.write(x)
-debug.write = _debugwrite
-
-ctx = context = threadeddict()
-
-ctx.__doc__ = """
-A `storage` object containing various information about the request:
-  
-`environ` (aka `env`)
-   : A dictionary containing the standard WSGI environment variables.
-
-`host`
-   : The domain (`Host` header) requested by the user.
-
-`home`
-   : The base path for the application.
-
-`ip`
-   : The IP address of the requester.
-
-`method`
-   : The HTTP method used.
-
-`path`
-   : The path request.
-   
-`query`
-   : If there are no query arguments, the empty string. Otherwise, a `?` followed
-     by the query string.
-
-`fullpath`
-   : The full path requested, including query arguments (`== path + query`).
-
-### Response Data
-
-`status` (default: "200 OK")
-   : The status code to be used in the response.
-
-`headers`
-   : A list of 2-tuples to be used in the response.
-
-`output`
-   : A string to be used as the response.
-"""
--- a/bundled/webpy/web/webopenid.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +0,0 @@
-"""openid.py: an openid library for web.py
-
-Notes:
-
- - This will create a file called .openid_secret_key in the 
-   current directory with your secret key in it. If someone 
-   has access to this file they can log in as any user. And 
-   if the app can't find this file for any reason (e.g. you 
-   moved the app somewhere else) then each currently logged 
-   in user will get logged out.
-
- - State must be maintained through the entire auth process 
-   -- this means that if you have multiple web.py processes 
-   serving one set of URLs or if you restart your app often 
-   then log ins will fail. You have to replace sessions and 
-   store for things to work.
-
- - We set cookies starting with "openid_".
-
-"""
-
-import os
-import random
-import hmac
-import __init__ as web
-import openid.consumer.consumer
-import openid.store.memstore
-
-sessions = {}
-store = openid.store.memstore.MemoryStore()
-
-def _secret():
-    try:
-        secret = file('.openid_secret_key').read()
-    except IOError:
-        # file doesn't exist
-        secret = os.urandom(20)
-        file('.openid_secret_key', 'w').write(secret)
-    return secret
-
-def _hmac(identity_url):
-    return hmac.new(_secret(), identity_url).hexdigest()
-
-def _random_session():
-    n = random.random()
-    while n in sessions:
-        n = random.random()
-    n = str(n)
-    return n
-
-def status():
-    oid_hash = web.cookies().get('openid_identity_hash', '').split(',', 1)
-    if len(oid_hash) > 1:
-        oid_hash, identity_url = oid_hash
-        if oid_hash == _hmac(identity_url):
-            return identity_url
-    return None
-
-def form(openid_loc):
-    oid = status()
-    if oid:
-        return '''
-        <form method="post" action="%s">
-          <img src="http://openid.net/login-bg.gif" alt="OpenID" />
-          <strong>%s</strong>
-          <input type="hidden" name="action" value="logout" />
-          <input type="hidden" name="return_to" value="%s" />
-          <button type="submit">log out</button>
-        </form>''' % (openid_loc, oid, web.ctx.fullpath)
-    else:
-        return '''
-        <form method="post" action="%s">
-          <input type="text" name="openid" value="" 
-            style="background: url(http://openid.net/login-bg.gif) no-repeat; padding-left: 18px; background-position: 0 50%%;" />
-          <input type="hidden" name="return_to" value="%s" />
-          <button type="submit">log in</button>
-        </form>''' % (openid_loc, web.ctx.fullpath)
-
-def logout():
-    web.setcookie('openid_identity_hash', '', expires=-1)
-
-class host:
-    def POST(self):
-        # unlike the usual scheme of things, the POST is actually called
-        # first here
-        i = web.input(return_to='/')
-        if i.get('action') == 'logout':
-            logout()
-            return web.redirect(i.return_to)
-
-        i = web.input('openid', return_to='/')
-
-        n = _random_session()
-        sessions[n] = {'webpy_return_to': i.return_to}
-        
-        c = openid.consumer.consumer.Consumer(sessions[n], store)
-        a = c.begin(i.openid)
-        f = a.redirectURL(web.ctx.home, web.ctx.home + web.ctx.fullpath)
-
-        web.setcookie('openid_session_id', n)
-        return web.redirect(f)
-
-    def GET(self):
-        n = web.cookies('openid_session_id').openid_session_id
-        web.setcookie('openid_session_id', '', expires=-1)
-        return_to = sessions[n]['webpy_return_to']
-
-        c = openid.consumer.consumer.Consumer(sessions[n], store)
-        a = c.complete(web.input(), web.ctx.home + web.ctx.fullpath)
-
-        if a.status.lower() == 'success':
-            web.setcookie('openid_identity_hash', _hmac(a.identity_url) + ',' + a.identity_url)
-
-        del sessions[n]
-        return web.redirect(return_to)
--- a/bundled/webpy/web/wsgi.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-"""
-WSGI Utilities
-(from web.py)
-"""
-
-import os, sys
-
-import http
-import webapi as web
-from utils import listget
-from net import validaddr, validip
-import httpserver
-    
-def runfcgi(func, addr=('localhost', 8000)):
-    """Runs a WSGI function as a FastCGI server."""
-    import flup.server.fcgi as flups
-    return flups.WSGIServer(func, multiplexed=True, bindAddress=addr).run()
-
-def runscgi(func, addr=('localhost', 4000)):
-    """Runs a WSGI function as an SCGI server."""
-    import flup.server.scgi as flups
-    return flups.WSGIServer(func, bindAddress=addr).run()
-
-def runwsgi(func):
-    """
-    Runs a WSGI-compatible `func` using FCGI, SCGI, or a simple web server,
-    as appropriate based on context and `sys.argv`.
-    """
-    
-    if os.environ.has_key('SERVER_SOFTWARE'): # cgi
-        os.environ['FCGI_FORCE_CGI'] = 'Y'
-
-    if (os.environ.has_key('PHP_FCGI_CHILDREN') #lighttpd fastcgi
-      or os.environ.has_key('SERVER_SOFTWARE')):
-        return runfcgi(func, None)
-    
-    if 'fcgi' in sys.argv or 'fastcgi' in sys.argv:
-        args = sys.argv[1:]
-        if 'fastcgi' in args: args.remove('fastcgi')
-        elif 'fcgi' in args: args.remove('fcgi')
-        if args:
-            return runfcgi(func, validaddr(args[0]))
-        else:
-            return runfcgi(func, None)
-    
-    if 'scgi' in sys.argv:
-        args = sys.argv[1:]
-        args.remove('scgi')
-        if args:
-            return runscgi(func, validaddr(args[0]))
-        else:
-            return runscgi(func)
-    
-    return httpserver.runsimple(func, validip(listget(sys.argv, 1, '')))
-    
-def _is_dev_mode():
-    # quick hack to check if the program is running in dev mode.
-    if os.environ.has_key('SERVER_SOFTWARE') \
-        or os.environ.has_key('PHP_FCGI_CHILDREN') \
-        or 'fcgi' in sys.argv or 'fastcgi' in sys.argv \
-        or 'mod_wsgi' in sys.argv:
-            return False
-    return True
-
-# When running the builtin-server, enable debug mode if not already set.
-web.config.setdefault('debug', _is_dev_mode())
--- a/bundled/webpy/web/wsgiserver/LICENSE.txt	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-Copyright (c) 2004-2007, CherryPy Team (team@cherrypy.org)
-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 of the CherryPy Team 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.
--- a/bundled/webpy/web/wsgiserver/__init__.py	Fri Jun 11 20:07:47 2010 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1794 +0,0 @@
-"""A high-speed, production ready, thread pooled, generic WSGI server.
-
-Simplest example on how to use this module directly
-(without using CherryPy's application machinery):
-
-    from cherrypy import wsgiserver
-    
-    def my_crazy_app(environ, start_response):
-        status = '200 OK'
-        response_headers = [('Content-type','text/plain')]
-        start_response(status, response_headers)
-        return ['Hello world!\n']
-    
-    server = wsgiserver.CherryPyWSGIServer(
-                ('0.0.0.0', 8070), my_crazy_app,
-                server_name='www.cherrypy.example')
-    
-The CherryPy WSGI server can serve as many WSGI applications 
-as you want in one instance by using a WSGIPathInfoDispatcher:
-    
-    d = WSGIPathInfoDispatcher({'/': my_crazy_app, '/blog': my_blog_app})
-    server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', 80), d)
-    
-Want SSL support? Just set these attributes:
-    
-    server.ssl_certificate = <filename>
-    server.ssl_private_key = <filename>
-    
-    if __name__ == '__main__':
-        try:
-            server.start()
-        except KeyboardInterrupt:
-            server.stop()
-
-This won't call the CherryPy engine (application side) at all, only the
-WSGI server, which is independant from the rest of CherryPy. Don't
-let the name "CherryPyWSGIServer" throw you; the name merely reflects
-its origin, not its coupling.
-
-For those of you wanting to understand internals of this module, here's the
-basic call flow. The server's listening thread runs a very tight loop,
-sticking incoming connections onto a Queue:
-
-    server = CherryPyWSGIServer(...)
-    server.start()
-    while True:
-        tick()
-        # This blocks until a request comes in:
-        child = socket.accept()
-        conn = HTTPConnection(child, ...)
-        server.requests.put(conn)
-
-Worker threads are kept in a pool and poll the Queue, popping off and then
-handling each connection in turn. Each connection can consist of an arbitrary
-number of requests and their responses, so we run a nested loop:
-
-    while True:
-        conn = server.requests.get()
-        conn.communicate()
-        ->  while True:
-                req = HTTPRequest(...)
-                req.parse_request()
-                ->  # Read the Request-Line, e.g. "GET /page HTTP/1.1"
-                    req.rfile.readline()
-                    req.read_headers()
-                req.respond()
-                ->  response = wsgi_app(...)
-                    try:
-                        for chunk in response:
-                            if chunk:
-                                req.write(chunk)
-                    finally:
-                        if hasattr(response, "close"):
-                            response.close()
-                if req.close_connection:
-                    return
-"""
-
-
-import base64
-import os
-import Queue
-import re
-quoted_slash = re.compile("(?i)%2F")
-import rfc822
-import socket
-try:
-    import cStringIO as StringIO
-except ImportError:
-    import StringIO
-
-_fileobject_uses_str_type = isinstance(socket._fileobject(None)._rbuf, basestring)
-
-import sys
-import threading
-import time
-import traceback
-from urllib import unquote
-from urlparse import urlparse
-import warnings
-
-try:
-    from OpenSSL import SSL
-    from OpenSSL import crypto
-except ImportError:
-    SSL = None
-
-import errno
-
-def plat_specific_errors(*errnames):
-    """Return error numbers for all errors in errnames on this platform.
-    
-    The 'errno' module contains different global constants depending on
-    the specific platform (OS). This function will return the list of
-    numeric values for a given list of potential names.
-    """
-    errno_names = dir(errno)
-    nums = [getattr(errno, k) for k in errnames if k in errno_names]
-    # de-dupe the list
-    return dict.fromkeys(nums).keys()
-
-socket_error_eintr = plat_specific_errors("EINTR", "WSAEINTR")
-
-socket_errors_to_ignore = plat_specific_errors(
-    "EPIPE",
-    "EBADF", "WSAEBADF",
-    "ENOTSOCK", "WSAENOTSOCK",
-    "ETIMEDOUT", "WSAETIMEDOUT",
-    "ECONNREFUSED", "WSAECONNREFUSED",
-    "ECONNRESET", "WSAECONNRESET",
-    "ECONNABORTED", "WSAECONNABORTED",
-    "ENETRESET", "WSAENETRESET",
-    "EHOSTDOWN", "EHOSTUNREACH",
-    )
-socket_errors_to_ignore.append("timed out")
-
-socket_errors_nonblocking = plat_specific_errors(
-    'EAGAIN', 'EWOULDBLOCK', 'WSAEWOULDBLOCK')
-
-comma_separated_headers = ['ACCEPT', 'ACCEPT-CHARSET', 'ACCEPT-ENCODING',
-    'ACCEPT-LANGUAGE', 'ACCEPT-RANGES', 'ALLOW', 'CACHE-CONTROL',
-    'CONNECTION', 'CONTENT-ENCODING', 'CONTENT-LANGUAGE', 'EXPECT',
-    'IF-MATCH', 'IF-NONE-MATCH', 'PRAGMA', 'PROXY-AUTHENTICATE', 'TE',
-    'TRAILER', 'TRANSFER-ENCODING', 'UPGRADE', 'VARY', 'VIA', 'WARNING',
-    'WWW-AUTHENTICATE']
-
-
-class WSGIPathInfoDispatcher(object):
-    """A WSGI dispatcher for dispatch based on the PATH_INFO.
-    
-    apps: a dict or list of (path_prefix, app) pairs.
-    """
-    
-    def __init__(self, apps):
-        try:
-            apps = apps.items()
-        except AttributeError:
-            pass
-        
-        # Sort the apps by len(path), descending
-        apps.sort()
-        apps.reverse()
-        
-        # The path_prefix strings must start, but not end, with a slash.
-        # Use "" instead of "/".
-        self.apps = [(p.rstrip("/"), a) for p, a in apps]
-    
-    def __call__(self, environ, start_response):
-        path = environ["PATH_INFO"] or "/"
-        for p, app in self.apps:
-            # The apps list should be sorted by length, descending.
-            if path.startswith(p + "/") or path == p:
-                environ = environ.copy()
-                environ["SCRIPT_NAME"] = environ["SCRIPT_NAME"] + p
-                environ["PATH_INFO"] = path[len(p):]
-                return app(environ, start_response)
-        
-        start_response('404 Not Found', [('Content-Type', 'text/plain'),
-                                         ('Content-Length', '0')])
-        return ['']
-
-
-class MaxSizeExceeded(Exception):
-    pass
-
-class SizeCheckWrapper(object):
-    """Wraps a file-like object, raising MaxSizeExceeded if too large."""
-    
-    def __init__(self, rfile, maxlen):
-        self.rfile = rfile
-        self.maxlen = maxlen
-        self.bytes_read = 0
-    
-    def _check_length(self):
-        if self.maxlen and self.bytes_read > self.maxlen:
-            raise MaxSizeExceeded()
-    
-    def read(self, size=None):
-        data = self.rfile.read(size)
-        self.bytes_read += len(data)
-        self._check_length()
-        return data
-    
-    def readline(self, size=None):
-        if size is not None:
-            data = self.rfile.readline(size)
-            self.bytes_read += len(data)
-            self._check_length()
-            return data
-        
-        # User didn't specify a size ...
-        # We read the line in chunks to make sure it's not a 100MB line !
-        res = []
-        while True:
-            data = self.rfile.readline(256)
-            self.bytes_read += len(data)
-            self._check_length()
-            res.append(data)
-            # See http://www.cherrypy.org/ticket/421
-            if len(data) < 256 or data[-1:] == "\n":
-                return ''.join(res)
-    
-    def readlines(self, sizehint=0):
-        # Shamelessly stolen from StringIO
-        total = 0
-        lines = []
-        line = self.readline()
-        while line:
-            lines.append(line)
-            total += len(line)
-            if 0 < sizehint <= total:
-                break
-            line = self.readline()
-        return lines
-    
-    def close(self):
-        self.rfile.close()
-    
-    def __iter__(self):
-        return self
-    
-    def next(self):
-        data = self.rfile.next()
-        self.bytes_read += len(data)
-        self._check_length()
-        return data
-
-
-class HTTPRequest(object):
-    """An HTTP Request (and response).
-    
-    A single HTTP connection may consist of multiple request/response pairs.
-    
-    send: the 'send' method from the connection's socket object.
-    wsgi_app: the WSGI application to call.
-    environ: a partial WSGI environ (server and connection entries).
-        The caller MUST set the following entries:
-        * All wsgi.* entries, including .input
-        * SERVER_NAME and SERVER_PORT
-        * Any SSL_* entries
-        * Any custom entries like REMOTE_ADDR and REMOTE_PORT
-        * SERVER_SOFTWARE: the value to write in the "Server" response header.
-        * ACTUAL_SERVER_PROTOCOL: the value to write in the Status-Line of
-            the response. From RFC 2145: "An HTTP server SHOULD send a
-            response version equal to the highest version for which the
-            server is at least conditionally compliant, and whose major
-            version is less than or equal to the one received in the
-            request.  An HTTP server MUST NOT send a version for which
-            it is not at least conditionally compliant."
-    
-    outheaders: a list of header tuples to write in the response.
-    ready: when True, the request has been parsed and is ready to begin
-        generating the response. When False, signals the calling Connection
-        that the response should not be generated and the connection should
-        close.
-    close_connection: signals the calling Connection that the request
-        should close. This does not imply an error! The client and/or
-        server may each request that the connection be closed.
-    chunked_write: if True, output will be encoded with the "chunked"
-        transfer-coding. This value is set automatically inside
-        send_headers.
-    """
-    
-    max_request_header_size = 0
-    max_request_body_size = 0
-    
-    def __init__(self, wfile, environ, wsgi_app):
-        self.rfile = environ['wsgi.input']
-        self.wfile = wfile
-        self.environ = environ.copy()
-        self.wsgi_app = wsgi_app
-        
-        self.ready = False
-        self.started_response = False
-        self.status = ""
-        self.outheaders = []
-        self.sent_headers = False
-        self.close_connection = False
-        self.chunked_write = False
-    
-    def parse_request(self):
-        """Parse the next HTTP request start-line and message-headers."""
-        self.rfile.maxlen = self.max_request_header_size
-        self.rfile.bytes_read = 0
-        
-        try:
-            self._parse_request()
-        except MaxSizeExceeded:
-            self.simple_response("413 Request Entity Too Large")
-            return
-    
-    def _parse_request(self):
-        # HTTP/1.1 connections are persistent by default. If a client
-        # requests a page, then idles (leaves the connection open),
-        # then rfile.readline() will raise socket.error("timed out").
-        # Note that it does this based on the value given to settimeout(),
-        # and doesn't need the client to request or acknowledge the close
-        # (although your TCP stack might suffer for it: cf Apache's history
-        # with FIN_WAIT_2).
-        request_line = self.rfile.readline()
-        if not request_line:
-            # Force self.ready = False so the connection will close.
-            self.ready = False
-            return
-        
-        if request_line == "\r\n":
-            # RFC 2616 sec 4.1: "...if the server is reading the protocol
-            # stream at the beginning of a message and receives a CRLF
-            # first, it should ignore the CRLF."
-            # But only ignore one leading line! else we enable a DoS.
-            request_line = self.rfile.readline()
-            if not request_line:
-                self.ready = False
-                return
-        
-        environ = self.environ
-        
-        try:
-            method, path, req_protocol = request_line.strip().split(" ", 2)
-        except ValueError:
-            self.simple_response(400, "Malformed Request-Line")
-            return
-        
-        environ["REQUEST_METHOD"] = method
-        
-        # path may be an abs_path (including "http://host.domain.tld");
-        scheme, location, path, params, qs, frag = urlparse(path)
-        
-        if frag:
-            self.simple_response("400 Bad Request",
-                                 "Illegal #fragment in Request-URI.")
-            return
-        
-        if scheme:
-            environ["wsgi.url_scheme"] = scheme
-        if params:
-            path = path + ";" + params
-        
-        environ["SCRIPT_NAME"] = ""
-        
-        # Unquote the path+params (e.g. "/this%20path" -> "this path").
-        # http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2
-        #
-        # But note that "...a URI must be separated into its components
-        # before the escaped characters within those components can be
-        # safely decoded." http://www.ietf.org/rfc/rfc2396.txt, sec 2.4.2
-        atoms = [unquote(x) for x in quoted_slash.split(path)]
-        path = "%2F".join(atoms)
-        environ["PATH_INFO"] = path
-        
-        # Note that, like wsgiref and most other WSGI servers,
-        # we unquote the path but not the query string.
-        environ["QUERY_STRING"] = qs
-        
-        # Compare request and server HTTP protocol versions, in case our
-        # server does not support the requested protocol. Limit our output
-        # to min(req, server). We want the following output:
-        #     request    server     actual written   supported response
-        #     protocol   protocol  response protocol    feature set
-        # a     1.0        1.0           1.0                1.0
-        # b     1.0        1.1           1.1                1.0
-        # c     1.1        1.0           1.0                1.0
-        # d     1.1        1.1           1.1                1.1
-        # Notice that, in (b), the response will be "HTTP/1.1" even though
-        # the client only understands 1.0. RFC 2616 10.5.6 says we should
-        # only return 505 if the _major_ version is different.
-        rp = int(req_protocol[5]), int(req_protocol[7])
-        server_protocol = environ["ACTUAL_SERVER_PROTOCOL"]
-        sp = int(server_protocol[5]), int(server_protocol[7])
-        if sp[0] != rp[0]:
-            self.simple_response("505 HTTP Version Not Supported")
-            return
-        # Bah. "SERVER_PROTOCOL" is actually the REQUEST protocol.
-        environ["SERVER_PROTOCOL"] = req_protocol
-        self.response_protocol = "HTTP/%s.%s" % min(rp, sp)
-        
-        # If the Request-URI was an absoluteURI, use its location atom.
-        if location:
-            environ["SERVER_NAME"] = location
-        
-        # then all the http headers
-        try:
-            self.read_headers()
-        except ValueError, ex:
-            self.simple_response("400 Bad Request", repr(ex.args))
-            return
-        
-        mrbs = self.max_request_body_size
-        if mrbs and int(environ.get("CONTENT_LENGTH", 0)) > mrbs:
-            self.simple_response("413 Request Entity Too Large")
-            return
-        
-        # Persistent connection support
-        if self.response_protocol == "HTTP/1.1":
-            # Both server and client are HTTP/1.1
-            if environ.get("HTTP_CONNECTION", "") == "close":
-                self.close_connection = True
-        else:
-            # Either the server or client (or both) are HTTP/1.0
-            if environ.get("HTTP_CONNECTION", "") != "Keep-Alive":
-                self.close_connection = True
-        
-        # Transfer-Encoding support
-        te = None
-        if self.response_protocol == "HTTP/1.1":
-            te = environ.get("HTTP_TRANSFER_ENCODING")
-            if te:
-                te = [x.strip().lower() for x in te.split(",") if x.strip()]
-        
-        self.chunked_read = False
-        
-        if te:
-            for enc in te:
-                if enc == "chunked":
-                    self.chunked_read = True
-                else:
-                    # Note that, even if we see "chunked", we must reject
-                    # if there is an extension we don't recognize.
-                    self.simple_response("501 Unimplemented")
-                    self.close_connection = True
-                    return
-        
-        # From PEP 333:
-        # "Servers and gateways that implement HTTP 1.1 must provide
-        # transparent support for HTTP 1.1's "expect/continue" mechanism.
-        # This may be done in any of several ways:
-        #   1. Respond to requests containing an Expect: 100-continue request
-        #      with an immediate "100 Continue" response, and proceed normally.
-        #   2. Proceed with the request normally, but provide the application
-        #      with a wsgi.input stream that will send the "100 Continue"
-        #      response if/when the application first attempts to read from
-        #      the input stream. The read request must then remain blocked
-        #      until the client responds.
-        #   3. Wait until the client decides that the server does not support
-        #      expect/continue, and sends the request body on its own.
-        #      (This is suboptimal, and is not recommended.)
-        #
-        # We used to do 3, but are now doing 1. Maybe we'll do 2 someday,
-        # but it seems like it would be a big slowdown for such a rare case.
-        if environ.get("HTTP_EXPECT", "") == "100-continue":
-            self.simple_response(100)
-        
-        self.ready = True
-    
-    def read_headers(self):
-        """Read header lines from the incoming stream."""
-        environ = self.environ
-        
-        while True:
-            line = self.rfile.readline()
-            if not line:
-                # No more data--illegal end of headers
-                raise ValueError("Illegal end of headers.")
-            
-            if line == '\r\n':
-                # Normal end of headers
-                break
-            
-            if line[0] in ' \t':
-                # It's a continuation line.
-                v = line.strip()
-            else:
-                k, v = line.split(":", 1)
-                k, v = k.strip().upper(), v.strip()
-                envname = "HTTP_" + k.replace("-", "_")
-            
-            if k in comma_separated_headers:
-                existing = environ.get(envname)
-                if existing:
-                    v = ", ".join((existing, v))
-            environ[envname] = v
-        
-        ct = environ.pop("HTTP_CONTENT_TYPE", None)
-        if ct is not None:
-            environ["CONTENT_TYPE"] = ct
-        cl = environ.pop("HTTP_CONTENT_LENGTH", None)
-        if cl is not None:
-            environ["CONTENT_LENGTH"] = cl
-    
-    def decode_chunked(self):
-        """Decode the 'chunked' transfer coding."""
-        cl = 0
-        data = StringIO.StringIO()
-        while True:
-            line = self.rfile.readline().strip().split(";", 1)
-            chunk_size = int(line.pop(0), 16)
-            if chunk_size <= 0:
-                break
-##            if line: chunk_extension = line[0]
-            cl += chunk_size
-            data.write(self.rfile.read(chunk_size))
-            crlf = self.rfile.read(2)
-            if crlf != "\r\n":
-                self.simple_response("400 Bad Request",
-                                     "Bad chunked transfer coding "
-                                     "(expected '\\r\\n', got %r)" % crlf)
-                return
-        
-        # Grab any trailer headers
-        self.read_headers()
-        
-        data.seek(0)
-        self.environ["wsgi.input"] = data
-        self.environ["CONTENT_LENGTH"] = str(cl) or ""
-        return True
-    
-    def respond(self):
-        """Call the appropriate WSGI app and write its iterable output."""
-        # Set rfile.maxlen to ensure we don't read past Content-Length.
-        # This will also be used to read the entire request body if errors
-        # are raised before the app can read the body.
-        if self.chunked_read:
-            # If chunked, Content-Length will be 0.
-            self.rfile.maxlen = self.max_request_body_size
-        else:
-            cl = int(self.environ.get("CONTENT_LENGTH", 0))
-            if self.max_request_body_size:
-                self.rfile.maxlen = min(cl, self.max_request_body_size)
-            else:
-                self.rfile.maxlen = cl
-        self.rfile.bytes_read = 0
-        
-        try:
-            self._respond()
-        except MaxSizeExceeded:
-            if not self.sent_headers:
-                self.simple_response("413 Request Entity Too Large")
-            return
-    
-    def _respond(self):
-        if self.chunked_read:
-            if not self.decode_chunked():
-                self.close_connection = True
-                return
-        
-        response = self.wsgi_app(self.environ, self.start_response)
-        try:
-            for chunk in response:
-                # "The start_response callable must not actually transmit
-                # the response headers. Instead, it must store them for the
-                # server or gateway to transmit only after the first
-                # iteration of the application return value that yields
-                # a NON-EMPTY string, or upon the application's first
-                # invocation of the write() callable." (PEP 333)
-                if chunk:
-                    self.write(chunk)
-        finally:
-            if hasattr(response, "close"):
-                response.close()
-        
-        if (self.ready and not self.sent_headers):
-            self.sent_headers = True
-            self.send_headers()
-        if self.chunked_write:
-            self.wfile.sendall("0\r\n\r\n")
-    
-    def simple_response(self, status, msg=""):
-        """Write a simple response back to the client."""
-        status = str(status)
-        buf = ["%s %s\r\n" % (self.environ['ACTUAL_SERVER_PROTOCOL'], status),
-               "Content-Length: %s\r\n" % len(msg),
-               "Content-Type: text/plain\r\n"]
-        
-        if status[:3] == "413" and self.response_protocol == 'HTTP/1.1':
-            # Request Entity Too Large
-            self.close_connection = True
-            buf.append("Connection: close\r\n")
-        
-        buf.append("\r\n")
-        if msg:
-            buf.append(msg)
-        
-        try:
-            self.wfile.sendall("".join(buf))
-        except socket.error, x:
-            if x.args[0] not in socket_errors_to_ignore:
-                raise
-    
-    def start_response(self, status, headers, exc_info = None):
-        """WSGI callable to begin the HTTP response."""
-        # "The application may call start_response more than once,
-        # if and only if the exc_info argument is provided."
-        if self.started_response and not exc_info:
-            raise AssertionError("WSGI start_response called a second "
-                                 "time with no exc_info.")
-        
-        # "if exc_info is provided, and the HTTP headers have already been
-        # sent, start_response must raise an error, and should raise the
-        # exc_info tuple."
-        if self.sent_headers:
-            try:
-                raise exc_info[0], exc_info[1], exc_info[2]
-            finally:
-                exc_info = None
-        
-        self.started_response = True
-        self.status = status
-        self.outheaders.extend(headers)
-        return self.write
-    
-    def write(self, chunk):
-        """WSGI callable to write unbuffered data to the client.
-        
-        This method is also used internally by start_response (to write
-        data from the iterable returned by the WSGI application).
-        """
-        if not self.started_response:
-            raise AssertionError("WSGI write called before start_response.")
-        
-        if not self.sent_headers:
-            self.sent_headers = True
-            self.send_headers()
-        
-        if self.chunked_write and chunk:
-            buf = [hex(len(chunk))[2:], "\r\n", chunk, "\r\n"]
-            self.wfile.sendall("".join(buf))
-        else:
-            self.wfile.sendall(chunk)
-    
-    def send_headers(self):
-        """Assert, process, and send the HTTP response message-headers."""
-        hkeys = [key.lower() for key, value in self.outheaders]
-        status = int(self.status[:3])
-        
-        if status == 413:
-            # Request Entity Too Large. Close conn to avoid garbage.
-            self.close_connection = True
-        elif "content-length" not in hkeys:
-            # "All 1xx (informational), 204 (no content),
-            # and 304 (not modified) responses MUST NOT
-            # include a message-body." So no point chunking.
-            if status < 200 or status in (204, 205, 304):
-                pass
-            else:
-                if (self.response_protocol == 'HTTP/1.1'
-                    and self.environ["REQUEST_METHOD"] != 'HEAD'):
-                    # Use the chunked transfer-coding
-                    self.chunked_write = True
-                    self.outheaders.append(("Transfer-Encoding", "chunked"))
-                else:
-                    # Closing the conn is the only way to determine len.
-                    self.close_connection = True
-        
-        if "connection" not in hkeys:
-            if self.response_protocol == 'HTTP/1.1':
-                # Both server and client are HTTP/1.1 or better
-                if self.close_connection:
-                    self.outheaders.append(("Connection", "close"))
-            else:
-                # Server and/or client are HTTP/1.0
-                if not self.close_connection:
-                    self.outheaders.append(("Connection", "Keep-Alive"))
-        
-        if (not self.close_connection) and (not self.chunked_read):
-            # Read any remaining request body data on the socket.
-            # "If an origin server receives a request that does not include an
-            # Expect request-header field with the "100-continue" expectation,
-            # the request includes a request body, and the server responds
-            # with a final status code before reading the entire request body
-            # from the transport connection, then the server SHOULD NOT close
-            # the transport connection until it has read the entire request,
-            # or until the client closes the connection. Otherwise, the client
-            # might not reliably receive the response message. However, this
-            # requirement is not be construed as preventing a server from
-            # defending itself against denial-of-service attacks, or from
-            # badly broken client implementations."
-            size = self.rfile.maxlen - self.rfile.bytes_read
-            if size > 0:
-                self.rfile.read(size)
-        
-        if "date" not in hkeys:
-            self.outheaders.append(("Date", rfc822.formatdate()))
-        
-        if "server" not in hkeys:
-            self.outheaders.append(("Server", self.environ['SERVER_SOFTWARE']))
-        
-        buf = [self.environ['ACTUAL_SERVER_PROTOCOL'], " ", self.status, "\r\n"]
-        try:
-            buf += [k + ": " + v + "\r\n" for k, v in self.outheaders]
-        except TypeError:
-            if not isinstance(k, str):
-                raise TypeError("WSGI response header key %r is not a string.")
-            if not isinstance(v, str):
-                raise TypeError("WSGI response header value %r is not a string.")
-            else:
-                raise
-        buf.append("\r\n")
-        self.wfile.sendall("".join(buf))
-
-
-class NoSSLError(Exception):
-    """Exception raised when a client speaks HTTP to an HTTPS socket."""
-    pass
-
-
-class FatalSSLAlert(Exception):
-    """Exception raised when the SSL implementation signals a fatal alert."""
-    pass
-
-
-if not _fileobject_uses_str_type:
-    class CP_fileobject(socket._fileobject):
-        """Faux file object attached to a socket object."""
-
-        def sendall(self, data):
-            """Sendall for non-blocking sockets."""
-            while data:
-                try:
-                    bytes_sent = self.send(data)
-                    data = data[bytes_sent:]
-                except socket.error, e:
-                    if e.args[0] not in socket_errors_nonblocking:
-                        raise
-
-        def send(self, data):
-            return self._sock.send(data)
-
-        def flush(self):
-            if self._wbuf:
-                buffer = "".join(self._wbuf)
-                self._wbuf = []
-                self.sendall(buffer)
-
-        def recv(self, size):
-            while True:
-                try:
-                    return self._sock.recv(size)
-                except socket.error, e:
-                    if (e.args[0] not in socket_errors_nonblocking
-                        and e.args[0] not in socket_error_eintr):
-                        raise
-
-        def read(self, size=-1):
-            # Use max, disallow tiny reads in a loop as they are very inefficient.
-            # We never leave read() with any leftover data from a new recv() call
-            # in our internal buffer.
-            rbufsize = max(self._rbufsize, self.default_bufsize)
-            # Our use of StringIO rather than lists of string objects returned by
-            # recv() minimizes memory usage and fragmentation that occurs when
-            # rbufsize is large compared to the typical return value of recv().
-            buf = self._rbuf
-            buf.seek(0, 2)  # seek end
-            if size < 0:
-                # Read until EOF
-                self._rbuf = StringIO.StringIO()  # reset _rbuf.  we consume it via buf.
-                while True:
-                    data = self.recv(rbufsize)
-                    if not data:
-                        break
-                    buf.write(data)
-                return buf.getvalue()
-            else:
-                # Read until size bytes or EOF seen, whichever comes first
-                buf_len = buf.tell()
-                if buf_len >= size:
-                    # Already have size bytes in our buffer?  Extract and return.
-                    buf.seek(0)
-                    rv = buf.read(size)
-                    self._rbuf = StringIO.StringIO()
-                    self._rbuf.write(buf.read())
-                    return rv
-
-                self._rbuf = StringIO.StringIO()  # reset _rbuf.  we consume it via buf.
-                while True:
-                    left = size - buf_len
-                    # recv() will malloc the amount of memory given as its
-                    # parameter even though it often returns much less data
-                    # than that.  The returned data string is short lived
-                    # as we copy it into a StringIO and free it.  This avoids
-                    # fragmentation issues on many platforms.
-                    data = self.recv(left)
-                    if not data:
-                        break
-                    n = len(data)
-                    if n == size and not buf_len:
-                        # Shortcut.  Avoid buffer data copies when:
-                        # - We have no data in our buffer.
-                        # AND
-                        # - Our call to recv returned exactly the
-                        #   number of bytes we were asked to read.
-                        return data
-                    if n == left:
-                        buf.write(data)
-                        del data  # explicit free
-                        break
-                    assert n <= left, "recv(%d) returned %d bytes" % (left, n)
-                    buf.write(data)
-                    buf_len += n
-                    del data  # explicit free
-                    #assert buf_len == buf.tell()
-                return buf.getvalue()
-
-        def readline(self, size=-1):
-            buf = self._rbuf
-            buf.seek(0, 2)  # seek end
-            if buf.tell() > 0:
-                # check if we already have it in our buffer
-                buf.seek(0)
-                bline = buf.readline(size)
-                if bline.endswith('\n') or len(bline) == size:
-                    self._rbuf = StringIO.StringIO()
-                    self._rbuf.write(buf.read())
-                    return bline
-                del bline
-            if size < 0:
-                # Read until \n or EOF, whichever comes first
-                if self._rbufsize <= 1:
-                    # Speed up unbuffered case
-                    buf.seek(0)
-                    buffers = [buf.read()]
-                    self._rbuf = StringIO.StringIO()  # reset _rbuf.  we consume it via buf.
-                    data = None
-                    recv = self.recv
-                    while data != "\n":
-                        data = recv(1)
-                        if not data:
-                            break
-                        buffers.append(data)
-                    return "".join(buffers)
-
-                buf.seek(0, 2)  # seek end
-                self._rbuf = StringIO.StringIO()  # reset _rbuf.  we consume it via buf.
-                while True:
-                    data = self.recv(self._rbufsize)
-                    if not data:
-                        break
-                    nl = data.find('\n')
-                    if nl >= 0:
-                        nl += 1
-                        buf.write(data[:nl])
-                        self._rbuf.write(data[nl:])
-                        del data
-                        break
-                    buf.write(data)
-                return buf.getvalue()
-            else:
-                # Read until size bytes or \n or EOF seen, whichever comes first
-                buf.seek(0, 2)  # seek end
-                buf_len = buf.tell()
-                if buf_len >= size:
-                    buf.seek(0)
-                    rv = buf.read(size)
-                    self._rbuf = StringIO.StringIO()
-                    self._rbuf.write(buf.read())
-                    return rv
-                self._rbuf = StringIO.StringIO()  # reset _rbuf.  we consume it via buf.
-                while True:
-                    data = self.recv(self._rbufsize)
-                    if not data:
-                        break
-                    left = size - buf_len
-                    # did we just receive a newline?
-                    nl = data.find('\n', 0, left)
-                    if nl >= 0:
-                        nl += 1
-                        # save the excess data to _rbuf
-                        self._rbuf.write(data[nl:])
-                        if buf_len:
-                            buf.write(data[:nl])
-                            break
-                        else:
-                            # Shortcut.  Avoid data copy through buf when returning
-                            # a substring of our first recv().
-                            return data[:nl]
-                    n = len(data)
-                    if n == size and not buf_len:
-                        # Shortcut.  Avoid data copy through buf when
-                        # returning exactly all of our first recv().
-                        return data
-                    if n >= left:
-                        buf.write(data[:left])
-                        self._rbuf.write(data[left:])
-                        break
-                    buf.write(data)
-                    buf_len += n
-                    #assert buf_len == buf.tell()
-                return buf.getvalue()
-
-else:
-    class CP_fileobject(socket._fileobject):
-        """Faux file object attached to a socket object."""
-
-        def sendall(self, data):
-            """Sendall for non-blocking sockets."""
-            while data:
-                try:
-                    bytes_sent = self.send(data)
-                    data = data[bytes_sent:]
-                except socket.error, e:
-                    if e.args[0] not in socket_errors_nonblocking:
-                        raise
-
-        def send(self, data):
-            return self._sock.send(data)
-
-        def flush(self):
-            if self._wbuf:
-                buffer = "".join(self._wbuf)
-                self._wbuf = []
-                self.sendall(buffer)
-
-        def recv(self, size):
-            while True:
-                try:
-                    return self._sock.recv(size)
-                except socket.error, e:
-                    if (e.args[0] not in socket_errors_nonblocking
-                        and e.args[0] not in socket_error_eintr):
-                        raise
-
-        def read(self, size=-1):
-            if size < 0:
-                # Read until EOF
-                buffers = [self._rbuf]
-                self._rbuf = ""
-                if self._rbufsize <= 1:
-                    recv_size = self.default_bufsize
-                else:
-                    recv_size = self._rbufsize
-
-                while True:
-                    data = self.recv(recv_size)
-                    if not data:
-                        break
-                    buffers.append(data)
-                return "".join(buffers)
-            else:
-                # Read until size bytes or EOF seen, whichever comes first
-                data = self._rbuf
-                buf_len = len(data)
-                if buf_len >= size:
-                    self._rbuf = data[size:]
-                    return data[:size]
-                buffers = []
-                if data:
-                    buffers.append(data)
-                self._rbuf = ""
-                while True:
-                    left = size - buf_len
-                    recv_size = max(self._rbufsize, left)
-                    data = self.recv(recv_size)
-                    if not data:
-                        break
-                    buffers.append(data)
-                    n = len(data)
-                    if n >= left:
-                        self._rbuf = data[left:]
-                        buffers[-1] = data[:left]
-                        break
-                    buf_len += n
-                return "".join(buffers)
-
-        def readline(self, size=-1):
-            data = self._rbuf
-            if size < 0:
-                # Read until \n or EOF, whichever comes first
-                if self._rbufsize <= 1:
-                    # Speed up unbuffered case
-                    assert data == ""
-                    buffers = []
-                    while data != "\n":
-                        data = self.recv(1)
-                        if not data:
-                            break
-                        buffers.append(data)
-                    return "".join(buffers)
-                nl = data.find('\n')
-                if nl >= 0:
-                    nl += 1
-                    self._rbuf = data[nl:]
-                    return data[:nl]
-                buffers = []
-                if data:
-                    buffers.append(data)
-                self._rbuf = ""
-                while True:
-                    data = self.recv(self._rbufsize)
-                    if not data:
-                        break
-                    buffers.append(data)
-                    nl = data.find('\n')
-                    if nl >= 0:
-                        nl += 1
-                        self._rbuf = data[nl:]
-                        buffers[-1] = data[:nl]
-                        break
-                return "".join(buffers)
-            else:
-                # Read until size bytes or \n or EOF seen, whichever comes first
-                nl = data.find('\n', 0, size)
-                if nl >= 0:
-                    nl += 1
-                    self._rbuf = data[nl:]
-                    return data[:nl]
-                buf_len = len(data)
-                if buf_len >= size:
-                    self._rbuf = data[size:]
-                    return data[:size]
-                buffers = []
-                if data:
-                    buffers.append(data)
-                self._rbuf = ""
-                while True:
-                    data = self.recv(self._rbufsize)
-                    if not data:
-                        break
-                    buffers.append(data)
-                    left = size - buf_len
-                    nl = data.find('\n', 0, left)
-                    if nl >= 0:
-                        nl += 1
-                        self._rbuf = data[nl:]
-                        buffers[-1] = data[:nl]
-                        break
-                    n = len(data)
-                    if n >= left:
-                        self._rbuf = data[left:]
-                        buffers[-1] = data[:left]
-                        break
-                    buf_len += n
-                return "".join(buffers)
-    
-
-class SSL_fileobject(CP_fileobject):
-    """SSL file object attached to a socket object."""
-    
-    ssl_timeout = 3
-    ssl_retry = .01
-    
-    def _safe_call(self, is_reader, call, *args, **kwargs):
-        """Wrap the given call with SSL error-trapping.
-        
-        is_reader: if False EOF errors will be raised. If True, EOF errors
-            will return "" (to emulate normal sockets).
-        """
-        start = time.time()
-        while True:
-            try:
-                return call(*args, **kwargs)
-            except SSL.WantReadError:
-                # Sleep and try again. This is dangerous, because it means
-                # the rest of the stack has no way of differentiating
-                # between a "new handshake" error and "client dropped".
-                # Note this isn't an endless loop: there's a timeout below.
-                time.sleep(self.ssl_retry)
-            except SSL.WantWriteError:
-                time.sleep(self.ssl_retry)
-            except SSL.SysCallError, e:
-                if is_reader and e.args == (-1, 'Unexpected EOF'):
-                    return ""
-                
-                errnum = e.args[0]
-                if is_reader and errnum in socket_errors_to_ignore:
-                    return ""
-                raise socket.error(errnum)
-            except SSL.Error, e:
-                if is_reader and e.args == (-1, 'Unexpected EOF'):
-                    return ""
-                
-                thirdarg = None
-                try:
-                    thirdarg = e.args[0][0][2]
-                except IndexError:
-                    pass
-                
-                if thirdarg == 'http request':
-                    # The client is talking HTTP to an HTTPS server.
-                    raise NoSSLError()
-                raise FatalSSLAlert(*e.args)
-            except:
-                raise
-            
-            if time.time() - start > self.ssl_timeout:
-                raise socket.timeout("timed out")
-
-    def recv(self, *args, **kwargs):
-        buf = []
-        r = super(SSL_fileobject, self).recv
-        while True:
-            data = self._safe_call(True, r, *args, **kwargs)
-            buf.append(data)
-            p = self._sock.pending()
-            if not p:
-                return "".join(buf)
-    
-    def sendall(self, *args, **kwargs):
-        return self._safe_call(False, super(SSL_fileobject, self).sendall, *args, **kwargs)
-
-    def send(self, *args, **kwargs):
-        return self._safe_call(False, super(SSL_fileobject, self).send, *args, **kwargs)
-
-
-class HTTPConnection(object):
-    """An HTTP connection (active socket).
-    
-    socket: the raw socket object (usually TCP) for this connection.
-    wsgi_app: the WSGI application for this server/connection.
-    environ: a WSGI environ template. This will be copied for each request.
-    
-    rfile: a fileobject for reading from the socket.
-    send: a function for writing (+ flush) to the socket.
-    """
-    
-    rbufsize = -1
-    RequestHandlerClass = HTTPRequest
-    environ = {"wsgi.version": (1, 0),
-               "wsgi.url_scheme": "http",
-               "wsgi.multithread": True,
-               "wsgi.multiprocess": False,
-               "wsgi.run_once": False,
-               "wsgi.errors": sys.stderr,
-               }
-    
-    def __init__(self, sock, wsgi_app, environ):
-        self.socket = sock
-        self.wsgi_app = wsgi_app
-        
-        # Copy the class environ into self.
-        self.environ = self.environ.copy()
-        self.environ.update(environ)
-        
-        if SSL and isinstance(sock, SSL.ConnectionType):
-            timeout = sock.gettimeout()
-            self.rfile = SSL_fileobject(sock, "rb", self.rbufsize)
-            self.rfile.ssl_timeout = timeout
-            self.wfile = SSL_fileobject(sock, "wb", -1)
-            self.wfile.ssl_timeout = timeout
-        else:
-            self.rfile = CP_fileobject(sock, "rb", self.rbufsize)
-            self.wfile = CP_fileobject(sock, "wb", -1)
-        
-        # Wrap wsgi.input but not HTTPConnection.rfile itself.
-        # We're also not setting maxlen yet; we'll do that separately
-        # for headers and body for each iteration of self.communicate
-        # (if maxlen is 0 the wrapper doesn't check length).
-        self.environ["wsgi.input"] = SizeCheckWrapper(self.rfile, 0)
-    
-    def communicate(self):
-        """Read each request and respond appropriately."""
-        try:
-            while True:
-                # (re)set req to None so that if something goes wrong in
-                # the RequestHandlerClass constructor, the error doesn't
-                # get written to the previous request.
-                req = None
-                req = self.RequestHandlerClass(self.wfile, self.environ,
-                                               self.wsgi_app)
-                
-                # This order of operations should guarantee correct pipelining.
-                req.parse_request()
-                if not req.ready:
-                    return
-                
-                req.respond()
-                if req.close_connection:
-                    return
-        
-        except socket.error, e:
-            errnum = e.args[0]
-            if errnum == 'timed out':
-                if req and not req.sent_headers:
-                    req.simple_response("408 Request Timeout")
-            elif errnum not in socket_errors_to_ignore:
-                if req and not req.sent_headers:
-                    req.simple_response("500 Internal Server Error",
-                                        format_exc())
-            return
-        except (KeyboardInterrupt, SystemExit):
-            raise
-        except FatalSSLAlert, e:
-            # Close the connection.
-            return
-        except NoSSLError:
-            if req and not req.sent_headers:
-                # Unwrap our wfile
-                req.wfile = CP_fileobject(self.socket._sock, "wb", -1)
-                req.simple_response("400 Bad Request",
-                    "The client sent a plain HTTP request, but "
-                    "this server only speaks HTTPS on this port.")
-                self.linger = True
-        except Exception, e:
-            if req and not req.sent_headers:
-                req.simple_response("500 Internal Server Error", format_exc())
-    
-    linger = False
-    
-    def close(self):
-        """Close the socket underlying this connection."""
-        self.rfile.close()
-        
-        if not self.linger:
-            # Python's socket module does NOT call close on the kernel socket
-            # when you call socket.close(). We do so manually here because we
-            # want this server to send a FIN TCP segment immediately. Note this
-            # must be called *before* calling socket.close(), because the latter
-            # drops its reference to the kernel socket.
-            self.socket._sock.close()
-            self.socket.close()
-        else:
-            # On the other hand, sometimes we want to hang around for a bit
-            # to make sure the client has a chance to read our entire
-            # response. Skipping the close() calls here delays the FIN
-            # packet until the socket object is garbage-collected later.
-            # Someday, perhaps, we'll do the full lingering_close that
-            # Apache does, but not today.
-            pass
-
-
-def format_exc(limit=None):
-    """Like print_exc() but return a string. Backport for Python 2.3."""
-    try:
-        etype, value, tb = sys.exc_info()
-        return ''.join(traceback.format_exception(etype, value, tb, limit))
-    finally:
-        etype = value = tb = None
-
-
-_SHUTDOWNREQUEST = None
-
-class WorkerThread(threading.Thread):
-    """Thread which continuously polls a Queue for Connection objects.
-    
-    server: the HTTP Server which spawned this thread, and which owns the
-        Queue and is placing active connections into it.
-    ready: a simple flag for the calling server to know when this thread
-        has begun polling the Queue.
-    
-    Due to the timing issues of polling a Queue, a WorkerThread does not
-    check its own 'ready' flag after it has started. To stop the thread,
-    it is necessary to stick a _SHUTDOWNREQUEST object onto the Queue
-    (one for each running WorkerThread).
-    """
-    
-    conn = None
-    
-    def __init__(self, server):
-        self.ready = False
-        self.server = server
-        threading.Thread.__init__(self)
-    
-    def run(self):
-        try:
-            self.ready = True
-            while True:
-                conn = self.server.requests.get()
-                if conn is _SHUTDOWNREQUEST:
-                    return
-                
-                self.conn = conn
-                try:
-                    conn.communicate()
-                finally:
-                    conn.close()
-                    self.conn = None
-        except (KeyboardInterrupt, SystemExit), exc:
-            self.server.interrupt = exc
-
-
-class ThreadPool(object):
-    """A Request Queue for the CherryPyWSGIServer which pools threads.
-    
-    ThreadPool objects must provide min, get(), put(obj), start()
-    and stop(timeout) attributes.
-    """
-    
-    def __init__(self, server, min=10, max=-1):
-        self.server = server
-        self.min = min
-        self.max = max
-        self._threads = []
-        self._queue = Queue.Queue()
-        self.get = self._queue.get
-    
-    def start(self):
-        """Start the pool of threads."""
-        for i in xrange(self.min):
-            self._threads.append(WorkerThread(self.server))
-        for worker in self._threads:
-            worker.setName("CP WSGIServer " + worker.getName())
-            worker.start()
-        for worker in self._threads:
-            while not worker.ready:
-                time.sleep(.1)
-    
-    def _get_idle(self):
-        """Number of worker threads which are idle. Read-only."""
-        return len([t for t in self._threads if t.conn is None])
-    idle = property(_get_idle, doc=_get_idle.__doc__)
-    
-    def put(self, obj):
-        self._queue.put(obj)
-        if obj is _SHUTDOWNREQUEST:
-            return
-    
-    def grow(self, amount):
-        """Spawn new worker threads (not above self.max)."""
-        for i in xrange(amount):
-            if self.max > 0 and len(self._threads) >= self.max:
-                break
-            worker = WorkerThread(self.server)
-            worker.setName("CP WSGIServer " + worker.getName())
-            self._threads.append(worker)
-            worker.start()
-    
-    def shrink(self, amount):
-        """Kill off worker threads (not below self.min)."""
-        # Grow/shrink the pool if necessary.
-        # Remove any dead threads from our list
-        for t in self._threads:
-            if not t.isAlive():
-                self._threads.remove(t)
-                amount -= 1
-        
-        if amount > 0:
-            for i in xrange(min(amount, len(self._threads) - self.min)):
-                # Put a number of shutdown requests on the queue equal
-                # to 'amount'. Once each of those is processed by a worker,
-                # that worker will terminate and be culled from our list
-                # in self.put.
-                self._queue.put(_SHUTDOWNREQUEST)
-    
-    def stop(self, timeout=5):
-        # Must shut down threads here so the code that calls
-        # this method can know when all threads are stopped.
-        for worker in self._threads:
-            self._queue.put(_SHUTDOWNREQUEST)
-        
-        # Don't join currentThread (when stop is called inside a request).
-        current = threading.currentThread()
-        while self._threads:
-            worker = self._threads.pop()
-            if worker is not current and worker.isAlive():
-                try:
-                    if timeout is None or timeout < 0:
-                        worker.join()
-                    else:
-                        worker.join(timeout)
-                        if worker.isAlive():
-                            # We exhausted the timeout.
-                            # Forcibly shut down the socket.
-                            c = worker.conn
-                            if c and not c.rfile.closed:
-                                if SSL and isinstance(c.socket, SSL.ConnectionType):
-                                    # pyOpenSSL.socket.shutdown takes no args
-                                    c.socket.shutdown()
-                                else:
-                                    c.socket.shutdown(socket.SHUT_RD)
-                            worker.join()
-                except (AssertionError,
-                        # Ignore repeated Ctrl-C.
-                        # See http://www.cherrypy.org/ticket/691.
-                        KeyboardInterrupt), exc1:
-                    pass
-
-
-
-class SSLConnection:
-    """A thread-safe wrapper for an SSL.Connection.
-    
-    *args: the arguments to create the wrapped SSL.Connection(*args).
-    """
-    
-    def __init__(self, *args):
-        self._ssl_conn = SSL.Connection(*args)
-        self._lock = threading.RLock()
-    
-    for f in ('get_context', 'pending', 'send', 'write', 'recv', 'read',
-              'renegotiate', 'bind', 'listen', 'connect', 'accept',
-              'setblocking', 'fileno', 'shutdown', 'close', 'get_cipher_list',
-              'getpeername', 'getsockname', 'getsockopt', 'setsockopt',
-              'makefile', 'get_app_data', 'set_app_data', 'state_string',
-              'sock_shutdown', 'get_peer_certificate', 'want_read',
-              'want_write', 'set_connect_state', 'set_accept_state',
-              'connect_ex', 'sendall', 'settimeout'):
-        exec """def %s(self, *args):
-        self._lock.acquire()
-        try:
-            return self._ssl_conn.%s(*args)
-        finally:
-            self._lock.release()
-""" % (f, f)
-
-
-try:
-    import fcntl
-except ImportError:
-    try:
-        from ctypes import windll, WinError
-    except ImportError:
-        def prevent_socket_inheritance(sock):
-            """Dummy function, since neither fcntl nor ctypes are available."""
-            pass
-    else:
-        def prevent_socket_inheritance(sock):
-            """Mark the given socket fd as non-inheritable (Windows)."""
-            if not windll.kernel32.SetHandleInformation(sock.fileno(), 1, 0):
-                raise WinError()
-else:
-    def prevent_socket_inheritance(sock):
-        """Mark the given socket fd as non-inheritable (POSIX)."""
-        fd = sock.fileno()
-        old_flags = fcntl.fcntl(fd, fcntl.F_GETFD)
-        fcntl.fcntl(fd, fcntl.F_SETFD, old_flags | fcntl.FD_CLOEXEC)
-
-
-class CherryPyWSGIServer(object):
-    """An HTTP server for WSGI.
-    
-    bind_addr: The interface on which to listen for connections.
-        For TCP sockets, a (host, port) tuple. Host values may be any IPv4
-        or IPv6 address, or any valid hostname. The string 'localhost' is a
-        synonym for '127.0.0.1' (or '::1', if your hosts file prefers IPv6).
-        The string '0.0.0.0' is a special IPv4 entry meaning "any active
-        interface" (INADDR_ANY), and '::' is the similar IN6ADDR_ANY for
-        IPv6. The empty string or None are not allowed.
-        
-        For UNIX sockets, supply the filename as a string.
-    wsgi_app: the WSGI 'application callable'; multiple WSGI applications
-        may be passed as (path_prefix, app) pairs.
-    numthreads: the number of worker threads to create (default 10).
-    server_name: the string to set for WSGI's SERVER_NAME environ entry.
-        Defaults to socket.gethostname().
-    max: the maximum number of queued requests (defaults to -1 = no limit).
-    request_queue_size: the 'backlog' argument to socket.listen();
-        specifies the maximum number of queued connections (default 5).
-    timeout: the timeout in seconds for accepted connections (default 10).
-    
-    nodelay: if True (the default since 3.1), sets the TCP_NODELAY socket
-        option.
-    
-    protocol: the version string to write in the Status-Line of all
-        HTTP responses. For example, "HTTP/1.1" (the default). This
-        also limits the supported features used in the response.
-    
-    
-    SSL/HTTPS
-    ---------
-    The OpenSSL module must be importable for SSL functionality.
-    You can obtain it from http://pyopenssl.sourceforge.net/
-    
-    ssl_certificate: the filename of the server SSL certificate.
-    ssl_privatekey: the filename of the server's private key file.
-    
-    If either of these is None (both are None by default), this server
-    will not use SSL. If both are given and are valid, they will be read
-    on server start and used in the SSL context for the listening socket.
-    """
-    
-    protocol = "HTTP/1.1"
-    _bind_addr = "127.0.0.1"
-    version = "CherryPy/3.1.2"
-    ready = False
-    _interrupt = None
-    
-    nodelay = True
-    
-    ConnectionClass = HTTPConnection
-    environ = {}
-    
-    # Paths to certificate and private key files
-    ssl_certificate = None
-    ssl_private_key = None
-    
-    def __init__(self, bind_addr, wsgi_app, numthreads=10, server_name=None,
-                 max=-1, request_queue_size=5, timeout=10, shutdown_timeout=5):
-        self.requests = ThreadPool(self, min=numthreads or 1, max=max)
-        
-        if callable(wsgi_app):
-            # We've been handed a single wsgi_app, in CP-2.1 style.
-            # Assume it's mounted at "".
-            self.wsgi_app = wsgi_app
-        else:
-            # We've been handed a list of (path_prefix, wsgi_app) tuples,
-            # so that the server can call different wsgi_apps, and also
-            # correctly set SCRIPT_NAME.
-            warnings.warn("The ability to pass multiple apps is deprecated "
-                          "and will be removed in 3.2. You should explicitly "
-                          "include a WSGIPathInfoDispatcher instead.",
-                          DeprecationWarning)
-            self.wsgi_app = WSGIPathInfoDispatcher(wsgi_app)
-        
-        self.bind_addr = bind_addr
-        if not server_name:
-            server_name = socket.gethostname()
-        self.server_name = server_name
-        self.request_queue_size = request_queue_size
-        
-        self.timeout = timeout
-        self.shutdown_timeout = shutdown_timeout
-    
-    def _get_numthreads(self):
-        return self.requests.min
-    def _set_numthreads(self, value):
-        self.requests.min = value
-    numthreads = property(_get_numthreads, _set_numthreads)
-    
-    def __str__(self):
-        return "%s.%s(%r)" % (self.__module__, self.__class__.__name__,
-                              self.bind_addr)
-    
-    def _get_bind_addr(self):
-        return self._bind_addr
-    def _set_bind_addr(self, value):
-        if isinstance(value, tuple) and value[0] in ('', None):
-            # Despite the socket module docs, using '' does not
-            # allow AI_PASSIVE to work. Passing None instead
-            # returns '0.0.0.0' like we want. In other words:
-            #     host    AI_PASSIVE     result
-            #      ''         Y         192.168.x.y
-            #      ''         N         192.168.x.y
-            #     None        Y         0.0.0.0
-            #     None        N         127.0.0.1
-            # But since you can get the same effect with an explicit
-            # '0.0.0.0', we deny both the empty string and None as values.
-            raise ValueError("Host values of '' or None are not allowed. "
-                             "Use '0.0.0.0' (IPv4) or '::' (IPv6) instead "
-                             "to listen on all active interfaces.")
-        self._bind_addr = value
-    bind_addr = property(_get_bind_addr, _set_bind_addr,
-        doc="""The interface on which to listen for connections.
-        
-        For TCP sockets, a (host, port) tuple. Host values may be any IPv4
-        or IPv6 address, or any valid hostname. The string 'localhost' is a
-        synonym for '127.0.0.1' (or '::1', if your hosts file prefers IPv6).
-        The string '0.0.0.0' is a special IPv4 entry meaning "any active
-        interface" (INADDR_ANY), and '::' is the similar IN6ADDR_ANY for
-        IPv6. The empty string or None are not allowed.
-        
-        For UNIX sockets, supply the filename as a string.""")
-    
-    def start(self):
-        """Run the server forever."""
-        # We don't have to trap KeyboardInterrupt or SystemExit here,
-        # because cherrpy.server already does so, calling self.stop() for us.
-        # If you're using this server with another framework, you should
-        # trap those exceptions in whatever code block calls start().
-        self._interrupt = None
-        
-        # Select the appropriate socket
-        if isinstance(self.bind_addr, basestring):
-            # AF_UNIX socket
-            
-            # So we can reuse the socket...
-            try: os.unlink(self.bind_addr)
-            except: pass
-            
-            # So everyone can access the socket...
-            try: os.chmod(self.bind_addr, 0777)
-            except: pass
-            
-            info = [(socket.AF_UNIX, socket.SOCK_STREAM, 0, "", self.bind_addr)]
-        else:
-            # AF_INET or AF_INET6 socket
-            # Get the correct address family for our host (allows IPv6 addresses)
-            host, port = self.bind_addr
-            try:
-                info = socket.getaddrinfo(host, port, socket.AF_UNSPEC,
-                                          socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
-            except socket.gaierror:
-                # Probably a DNS issue. Assume IPv4.
-                info = [(socket.AF_INET, socket.SOCK_STREAM, 0, "", self.bind_addr)]
-        
-        self.socket = None
-        msg = "No socket could be created"
-        for res in info:
-            af, socktype, proto, canonname, sa = res
-            try:
-                self.bind(af, socktype, proto)
-            except socket.error, msg:
-                if self.socket:
-                    self.socket.close()
-                self.socket = None
-                continue
-            break
-        if not self.socket:
-            raise socket.error, msg
-        
-        # Timeout so KeyboardInterrupt can be caught on Win32
-        self.socket.settimeout(1)
-        self.socket.listen(self.request_queue_size)
-        
-        # Create worker threads
-        self.requests.start()
-        
-        self.ready = True
-        while self.ready:
-            self.tick()
-            if self.interrupt:
-                while self.interrupt is True:
-                    # Wait for self.stop() to complete. See _set_interrupt.
-                    time.sleep(0.1)
-                if self.interrupt:
-                    raise self.interrupt
-    
-    def bind(self, family, type, proto=0):
-        """Create (or recreate) the actual socket object."""
-        self.socket = socket.socket(family, type, proto)
-        prevent_socket_inheritance(self.socket)
-        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-        if self.nodelay:
-            self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
-        if self.ssl_certificate and self.ssl_private_key:
-            if SSL is None:
-                raise ImportError("You must install pyOpenSSL to use HTTPS.")
-            
-            # See http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/442473
-            ctx = SSL.Context(SSL.SSLv23_METHOD)
-            ctx.use_privatekey_file(self.ssl_private_key)
-            ctx.use_certificate_file(self.ssl_certificate)
-            self.socket = SSLConnection(ctx, self.socket)
-            self.populate_ssl_environ()
-            
-            # If listening on the IPV6 any address ('::' = IN6ADDR_ANY),
-            # activate dual-stack. See http://www.cherrypy.org/ticket/871.
-            if (not isinstance(self.bind_addr, basestring)
-                and self.bind_addr[0] == '::' and family == socket.AF_INET6):
-                try:
-                    self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
-                except (AttributeError, socket.error):
-                    # Apparently, the socket option is not available in
-                    # this machine's TCP stack
-                    pass
-        
-        self.socket.bind(self.bind_addr)
-    
-    def tick(self):
-        """Accept a new connection and put it on the Queue."""
-        try:
-            s, addr = self.socket.accept()
-            prevent_socket_inheritance(s)
-            if not self.ready:
-                return
-            if hasattr(s, 'settimeout'):
-                s.settimeout(self.timeout)
-            
-            environ = self.environ.copy()
-            # SERVER_SOFTWARE is common for IIS. It's also helpful for
-            # us to pass a default value for the "Server" response header.
-            if environ.get("SERVER_SOFTWARE") is None:
-                environ["SERVER_SOFTWARE"] = "%s WSGI Server" % self.version
-            # set a non-standard environ entry so the WSGI app can know what
-            # the *real* server protocol is (and what features to support).
-            # See http://www.faqs.org/rfcs/rfc2145.html.
-            environ["ACTUAL_SERVER_PROTOCOL"] = self.protocol
-            environ["SERVER_NAME"] = self.server_name
-            
-            if isinstance(self.bind_addr, basestring):
-                # AF_UNIX. This isn't really allowed by WSGI, which doesn't
-                # address unix domain sockets. But it's better than nothing.
-                environ["SERVER_PORT"] = ""
-            else:
-                environ["SERVER_PORT"] = str(self.bind_addr[1])
-                # optional values
-                # Until we do DNS lookups, omit REMOTE_HOST
-                environ["REMOTE_ADDR"] = addr[0]
-                environ["REMOTE_PORT"] = str(addr[1])
-            
-            conn = self.ConnectionClass(s, self.wsgi_app, environ)
-            self.requests.put(conn)
-        except socket.timeout:
-            # The only reason for the timeout in start() is so we can
-            # notice keyboard interrupts on Win32, which don't interrupt
-            # accept() by default
-            return
-        except socket.error, x:
-            if x.args[0] in socket_error_eintr:
-                # I *think* this is right. EINTR should occur when a signal
-                # is received during the accept() call; all docs say retry
-                # the call, and I *think* I'm reading it right that Python
-                # will then go ahead and poll for and handle the signal
-                # elsewhere. See http://www.cherrypy.org/ticket/707.
-                return
-            if x.args[0] in socket_errors_nonblocking:
-                # Just try again. See http://www.cherrypy.org/ticket/479.
-                return
-            if x.args[0] in socket_errors_to_ignore:
-                # Our socket was closed.
-                # See http://www.cherrypy.org/ticket/686.
-                return
-            raise
-    
-    def _get_interrupt(self):
-        return self._interrupt
-    def _set_interrupt(self, interrupt):
-        self._interrupt = True
-        self.stop()
-        self._interrupt = interrupt
-    interrupt = property(_get_interrupt, _set_interrupt,
-                         doc="Set this to an Exception instance to "
-                             "interrupt the server.")
-    
-    def stop(self):
-        """Gracefully shutdown a server that is serving forever."""
-        self.ready = False
-        
-        sock = getattr(self, "socket", None)
-        if sock:
-            if not isinstance(self.bind_addr, basestring):
-                # Touch our own socket to make accept() return immediately.
-                try:
-                    host, port = sock.getsockname()[:2]
-                except socket.error, x:
-                    if x.args[0] not in socket_errors_to_ignore:
-                        raise
-                else:
-                    # Note that we're explicitly NOT using AI_PASSIVE,
-                    # here, because we want an actual IP to touch.
-                    # localhost won't work if we've bound to a public IP,
-                    # but it will if we bound to '0.0.0.0' (INADDR_ANY).
-                    for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC,
-                                                  socket.SOCK_STREAM):
-                        af, socktype, proto, canonname, sa = res
-                        s = None
-                        try:
-                            s = socket.socket(af, socktype, proto)
-                            # See http://groups.google.com/group/cherrypy-users/
-                            #        browse_frm/thread/bbfe5eb39c904fe0
-                            s.settimeout(1.0)
-                            s.connect((host, port))
-                            s.close()
-                        except socket.error:
-                            if s:
-                                s.close()
-            if hasattr(sock, "close"):
-                sock.close()
-            self.socket = None
-        
-        self.requests.stop(self.shutdown_timeout)
-    
-    def populate_ssl_environ(self):
-        """Create WSGI environ entries to be merged into each request."""
-        cert = open(self.ssl_certificate, 'rb').read()
-        cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert)
-        ssl_environ = {
-            "wsgi.url_scheme": "https",
-            "HTTPS": "on",
-            # pyOpenSSL doesn't provide access to any of these AFAICT
-##            'SSL_PROTOCOL': 'SSLv2',
-##            SSL_CIPHER 	string 	The cipher specification name
-##            SSL_VERSION_INTERFACE 	string 	The mod_ssl program version
-##            SSL_VERSION_LIBRARY 	string 	The OpenSSL program version
-            }
-        
-        # Server certificate attributes
-        ssl_environ.update({
-            'SSL_SERVER_M_VERSION': cert.get_version(),
-            'SSL_SERVER_M_SERIAL': cert.get_serial_number(),
-##            'SSL_SERVER_V_START': Validity of server's certificate (start time),
-##            'SSL_SERVER_V_END': Validity of server's certificate (end time),
-            })
-        
-        for prefix, dn in [("I", cert.get_issuer()),
-                           ("S", cert.get_subject())]:
-            # X509Name objects don't seem to have a way to get the
-            # complete DN string. Use str() and slice it instead,
-            # because str(dn) == "<X509Name object '/C=US/ST=...'>"
-            dnstr = str(dn)[18:-2]
-            
-            wsgikey = 'SSL_SERVER_%s_DN' % prefix
-            ssl_environ[wsgikey] = dnstr
-            
-            # The DN should be of the form: /k1=v1/k2=v2, but we must allow
-            # for any value to contain slashes itself (in a URL).
-            while dnstr:
-                pos = dnstr.rfind("=")
-                dnstr, value = dnstr[:pos], dnstr[pos + 1:]
-                pos = dnstr.rfind("/")
-                dnstr, key = dnstr[:pos], dnstr[pos + 1:]
-                if key and value:
-                    wsgikey = 'SSL_SERVER_%s_DN_%s' % (prefix, key)
-                    ssl_environ[wsgikey] = value
-        
-        self.environ.update(ssl_environ)
-