[Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - IFilesystemAccess.py:1.1.4.1 IPosixFileSystem.py:1.1.4.1 IReadFileSystem.py:1.1.4.1 IUsernamePassword.py:1.1.4.1 IWriteFileSystem.py:1.1.4.1 OSFileSystem.py:1.1.4.1 PublisherFileSystem.py:1.1.4.1 TestFilesystemAccess.py:1.1.4.1 UsernamePassword.py:1.1.4.1 __init__.py:1.1.4.1

Shane Hathaway shane@cvs.zope.org
Fri, 12 Apr 2002 17:31:00 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/Server/VFS
In directory cvs.zope.org:/tmp/cvs-serv20835/lib/python/Zope/Server/VFS

Added Files:
      Tag: Zope-3x-branch
	IFilesystemAccess.py IPosixFileSystem.py IReadFileSystem.py 
	IUsernamePassword.py IWriteFileSystem.py OSFileSystem.py 
	PublisherFileSystem.py TestFilesystemAccess.py 
	UsernamePassword.py __init__.py 
Log Message:
Merged Zope3-Server-Branch.


=== Added File Zope3/lib/python/Zope/Server/VFS/IFilesystemAccess.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""

$Id: IFilesystemAccess.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $
"""

from Interface import Interface

# XXX This interface should be in a more central location.

class IFilesystemAccess(Interface):
    """Provides authenticated access to a filesystem.
    """

    def authenticate(credentials):
        """Verifies filesystem access based on the presented credentials.

        Should raise Unauthorized if the user can not be authenticated.

        This method only checks general access and is not used for each
        call to open().  Rather, open() should do its own verification.
        """

    def open(credentials):
        """Returns an IReadFilesystem or IWriteFilesystem.

        Should raise Unauthorized if the user can not be authenticated.
        """


=== Added File Zope3/lib/python/Zope/Server/VFS/IPosixFileSystem.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""

$Id: IPosixFileSystem.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $
"""

from IWriteFileSystem import IWriteFileSystem
from IReadFileSystem import IReadFileSystem


class IPosixFileSystem(IWriteFileSystem, IReadFileSystem):
    """
    """

    def chmod(path, mode):
        """Change the access permissions of a file.
        """

    def chown(path, uid, gid):
        """Change the owner and group id of path to numeric uid and gid.
        """

    def link(src, dst):
        """Create a heard link to a file.
        """

    def mkfifo(path, mode=777):
        """Create a FIFO (a POSIX named pipe).
        """

    def symlink(src, dst):
        """Create a symbolic link at dst pointing to src.
        """



=== Added File Zope3/lib/python/Zope/Server/VFS/IReadFileSystem.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""

$Id: IReadFileSystem.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $
"""

from Interface import Interface

class IReadFileSystem(Interface):
    """We want to provide a complete wrapper around any and all read
       filesystem operations.

       Opening files for reading, and listing directories, should
       return a producer.

       All paths are POSIX paths, even when run on Windows,
       which mainly means that FS implementations always expect forward
       slashes, and filenames are case-sensitive.

       Note: A file system should *not* store any state!
    """

    def exists(path):
        """Test whether a path exists.
        """

    def isdir(path):
        """Test whether a path is a directory.
        """

    def isfile(path):
        """Test whether a path is a file.
        """

    def listdir(path, with_stats=0, pattern='*'):
        """Return a listing of the directory at 'path' The empty
           string indicates the current directory.  If 'with_stats' is set,
           instead return a list of (name, stat_info) tuples. All file
           names are filtered by the globbing pattern.  (See the 'glob'
           module in the Python standard library.)
        """
        return list(tuple(str, str))

    def readfile(path, mode, outstream, start=0, end=-1):
        """Outputs the file at path to a stream.
        """

    def stat(path):
        """Return the equivalent of os.stat() on the given path:

           (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime)
        """


=== Added File Zope3/lib/python/Zope/Server/VFS/IUsernamePassword.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""

$Id: IUsernamePassword.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $
"""

from Interface import Interface

# XXX These interfaces should be located in a more central location.
# (so I don't mind putting them together in one module for now ;-) )


class ICredentials(Interface):
    """Base interface for presentation of authentication credentials.

    Different kinds of credentials include username/password, client
    certificate, IP address and port, etc., including combinations.
    """


class IUsernamePassword(ICredentials):
    """A type of authentication credentials consisting of user name and
    password.  The most recognized form of credentials.
    """

    def getUserName():
        """Returns the user name presented for authentication.
        """

    def getPassword():
        """Returns the password presented for authentication.
        """



=== Added File Zope3/lib/python/Zope/Server/VFS/IWriteFileSystem.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""

$Id: IWriteFileSystem.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $
"""

from Interface import Interface

class IWriteFileSystem(Interface):
    """We want to provide a complete wrapper around any and all write
       filesystem operations.

       Notes:
         - A file system should *not* store any state!
         - Most of the commands copy the functionality given in os.
    """

    def mkdir(path, mode=777):
        """Create a directory.
        """

    def remove(path):
        """Remove a file. Same as unlink.
        """

    def rmdir(path):
        """Remove a directory.
        """

    def rename(old, new):
        """Rename a file or directory.
        """

    def writefile(path, mode, instream, start=0):
        """Write data to a file.
        """

    def check_writable(path):
        """Ensures a path is writable.  Throws an IOError if not."""



=== Added File Zope3/lib/python/Zope/Server/VFS/OSFileSystem.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""

$Id: OSFileSystem.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $
"""
import os
import re
import stat
import time
import fnmatch

from IPosixFileSystem import IPosixFileSystem


class OSFileSystem(object):
    """Generic OS FileSystem implementation.

       The root of this file system is a string describing the path
       to the directory used as root.
    """

    __implements__ = IPosixFileSystem

    copy_bytes = 65536


    def __init__ (self, root):
        self.root = root

    ############################################################
    # Implementation methods for interface
    # Zope.Server.VFS.IPosixFileSystem.IPosixFileSystem

    def chmod(self, path, mode):
        'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
        p = self.translate (path)
        return os.chmod(p, mode)


    def chown(self, path, uid, gid):
        'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
        p = self.translate (path)
        return os.chown(p, uid, gid)


    def link(self, src, dst):
        'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
        src = self.translate(src)
        dst = self.translate(dst)
        return os.link(src, dst)


    def mkfifo(self, path, mode=6*2**6):
        'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
        return os.mkfifo(path, mode)


    def symlink(self, src, dst):
        'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
        src = self.translate(src)
        dst = self.translate(dst)
        return os.symlink(src, dst)


    ######################################
    # from: Zope.Server.VFS.IReadFileSystem.IReadFileSystem

    def exists(self, path):
        'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
        p = self.translate(path)
        return os.path.exists(p)


    def isdir(self, path):
        'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
        p = self.translate(path)
        return os.path.isdir(p)


    def isfile(self, path):
        'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
        p = self.translate(path)
        return os.path.isfile(p)


    def listdir(self, path, with_stats=0, pattern='*'):
        'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
        p = self.translate(path)
        # list the directory's files
        ld = os.listdir(p)
        # filter them using the pattern
        ld = filter(lambda f, p=pattern, fnm=fnmatch.fnmatch: fnm(f, p), ld)
        # sort them alphabetically
        ld.sort()
        if not with_stats:
            result = ld
        else:
            result = []
            for file in ld:
                path = os.path.join(p, file)
                stat = safe_stat(path)
                if stat is not None:
                    result.append((file, stat))
        return result


    def readfile(self, path, mode, outstream, start=0, end=-1):
        'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
        p = self.translate(path)
        instream = open(p, mode)
        if start:
            instream.seek(start)
        pos = start
        while end < 0 or pos < end:
            toread = self.copy_bytes
            if end >= 0:
                toread = min(toread, end - pos)
            data = instream.read(toread)
            if not data:
                break
            pos += len(data)
            outstream.write(data)


    def stat(self, path):
        'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
        p = self.translate(path)
        return os.stat(p)


    ######################################
    # from: Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem

    def mkdir(self, path, mode=6*2**6):
        'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
        p = self.translate(path)
        return os.mkdir(p, mode)


    def remove(self, path):
        'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
        p = self.translate (path)
        return os.remove(p)


    def rmdir(self, path):
        'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
        p = self.translate (path)
        return os.rmdir(p)


    def rename(self, old, new):
        'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
        old = self.translate(old)
        new = self.translate(new)
        return os.rename(old, new)


    def writefile(self, path, mode, instream, start=0):
        'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
        p = self.translate(path)
        outstream = open(p, mode)
        if start:
            outstream.seek(start)
        while 1:
            data = instream.read(self.copy_bytes)
            if not data:
                break
            outstream.write(data)

    def check_writable(self, path):
        'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
        p = self.translate(path)
        if os.path.exists(p):
            remove = 0
        else:
            remove = 1
        f = open(p, 'a')  # append mode
        f.close()
        if remove:
            os.remove(p)

    #
    ############################################################


    # utility methods

    def normalize (self, path):
        # watch for the ever-sneaky '/+' path element
        # XXX It is unclear why "/+" is dangerous.  It is definitely
        # unexpected.
        path = re.sub('/+', '/', path)
        path = os.path.normpath(path)
        if path.startswith('..'):
            # Someone is trying to get lower than the permitted root.
            # We just ignore it.
            path = '/'
        return path


    def translate (self, path):
        """We need to join together three separate path components,
           and do it safely.  <real_root>/<path>
           use the operating system's path separator.

           We need to be extremly careful to include the cases where a hacker
           could attempt to a directory below root!
        """
        # Normalize the directory
        path = self.normalize(path)
        # Prepare for joining with root
        while path.startswith('/'):
            path = path[1:]
        # Join path with root
        return os.path.join(self.root, path)


    def __repr__ (self):
        return '<OSFileSystem, root=%s>' % self.root



def safe_stat (path):
    try:
        return os.stat(path)
    except:
        return None


=== Added File Zope3/lib/python/Zope/Server/VFS/PublisherFileSystem.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""

$Id: PublisherFileSystem.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $
"""

import os, re
import stat
import time

from cStringIO import StringIO

from IReadFileSystem import IReadFileSystem
from IWriteFileSystem import IWriteFileSystem

from Zope.Publisher.Publish import publish



class NoOutput:
    """An output stream lookalike that warns you if you try to
    dump anything into it."""

    def write(self, data):
        raise RuntimeError, "Not a writable stream"

    def flush(self):
        pass

    close = flush



class PublisherFileSystem:
    """Generic Publisher FileSystem implementation.
    """

    __implements__ = IReadFileSystem, IWriteFileSystem

    def __init__ (self, credentials, request_factory):
        self.credentials = credentials
        self.request_factory = request_factory


    def _execute(self, path, command, env=None):
        if env is None:
            env = {}

        env['command'] = command
        env['path'] = path
        env['credentials'] = self.credentials
        # NoOutput avoids creating a black hole.
        request = self.request_factory(StringIO(''), NoOutput(), env)
        # Note that publish() calls close() on request, which deletes the
        # response from the request, so that we need to keep track of it.
        response = request.getResponse()
        publish(request)
        return response.getResult()


    ############################################################
    # Implementation methods for interface
    # Zope.Server.VFS.IReadFileSystem.

    def exists(self, path):
        'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
        path = self.translate(path)
        if path == '/':
            return 1
        path, file = os.path.split(path)
        env = {'name': file}
        return self._execute(path, 'exists', env)


    def isdir(self, path):
        'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
        path = self.translate(path)
        return self._execute(path, 'isdir')


    def isfile(self, path):
        'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
        path = self.translate(path)
        return self._execute(path, 'isfile')


    def listdir(self, path, with_stats=0, pattern='*'):
        'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
        path = self.translate(path)
        env = {'with_stats' : with_stats,
               'pattern' : pattern}
        return self._execute(path, 'listdir', env)


    def readfile(self, path, mode, outstream, start=0, end=-1):
        'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
        path = self.translate(path)
        env = {'mode'      : mode,
               'outstream' : outstream,
               'start'     : start,
               'end'       : end}
        return self._execute(path, 'read', env)


    def stat(self, path):
        'See Zope.Server.VFS.IReadFileSystem.IReadFileSystem'
        path = self.translate(path)
        return self._execute(path, 'stat')

    #
    ############################################################

    ############################################################
    # Implementation methods for interface
    # Zope.Server.VFS.IWriteFileSystem.

    def mkdir(self, path, mode=777):
        'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
        path = self.translate(path)
        path, dir = os.path.split(path)
        env = {'name': dir}
        return self._execute(path, 'mkdir', env)


    def remove(self, path):
        'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
        path = self.translate(path)
        path, name = os.path.split(path)
        env = {'name': name}
        return self._execute(path, 'remove', env)


    def rmdir(self, path):
        'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
        path = self.translate(path)
        path, dir = os.path.split(path)
        env = {'name': dir}
        return self._execute(path, 'rmdir', env)


    def rename(self, old, new):
        'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
        old = self.translate(old)
        new = self.translate(new)
        path0, old = os.path.split(old)
        path1, new = os.path.split(new)
        assert path0 == path1
        env = {'old' : old,
               'new' : new}
        return self._execute(path0, 'rename', env)

    def writefile(self, path, mode, instream, start=0):
        'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
        path = self.translate(path)
        path, name = os.path.split(path)
        env = {'name'      : name,
               'mode'      : mode,
               'instream'  : instream,
               'start'     : start}
        return self._execute(path, 'writefile', env)


    def check_writable(self, path):
        'See Zope.Server.VFS.IWriteFileSystem.IWriteFileSystem'
        path = self.translate(path)
        path, name = os.path.split(path)
        env = {'name'      : name}
        return self._execute(path, 'check_writable', env)

    #
    ############################################################

    # utility methods

    def translate (self, path):
        # Normalize
        path = os.path.normpath(path)
        if path.startswith('..'):
            # Someone is trying to get lower than the permitted root.
            # We just ignore it.
            path = '/'
        return path



=== Added File Zope3/lib/python/Zope/Server/VFS/TestFilesystemAccess.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Implementation of IFilesystemAccess intended only for testing.

$Id: TestFilesystemAccess.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $
"""

from Zope.Server.VFS.IFilesystemAccess import IFilesystemAccess
from Zope.Server.VFS.IUsernamePassword import IUsernamePassword
from Zope.Exceptions import Unauthorized


class TestFilesystemAccess:

    __implements__ = IFilesystemAccess

    passwords = {'foo': 'bar'}

    def __init__(self, fs):
        self.fs = fs

    def authenticate(self, credentials):
        if not IUsernamePassword.isImplementedBy(credentials):
            raise Unauthorized
        name = credentials.getUserName()
        if not self.passwords.has_key(name):
            raise Unauthorized
        if credentials.getPassword() != self.passwords[name]:
            raise Unauthorized

    def open(self, credentials):
        self.authenticate(credentials)
        return self.fs



=== Added File Zope3/lib/python/Zope/Server/VFS/UsernamePassword.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""

$Id: UsernamePassword.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $
"""

from Zope.Server.VFS.IUsernamePassword import IUsernamePassword


class UsernamePassword:

    __implements__ = IUsernamePassword

    def __init__(self, username, password):
        self.username = username
        self.password = password

    def getUserName(self):
        return self.username

    def getPassword(self):
        return self.password



=== Added File Zope3/lib/python/Zope/Server/VFS/__init__.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""

$Id: __init__.py,v 1.1.4.1 2002/04/12 21:30:58 shane Exp $
"""