[Zope-Checkins] CVS: Zope3/lib/python/Zope/Server/VFS - IFileSystem.py:1.1.2.1 ListProducer.py:1.1.2.1 MSDOSFileSystem.py:1.1.2.1 MergedFileSystem.py:1.1.2.1 OSFileSystem.py:1.1.2.1 UnixFileSystem.py:1.1.2.1 ZODBFileSystem.py:1.1.2.1 __init__.py:1.1.2.1

Stephan Richter srichter@cbu.edu
Tue, 2 Apr 2002 00:08:09 -0500


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

Added Files:
      Tag: Zope3-Server-Branch
	IFileSystem.py ListProducer.py MSDOSFileSystem.py 
	MergedFileSystem.py OSFileSystem.py UnixFileSystem.py 
	ZODBFileSystem.py __init__.py 
Log Message:
Issue 53: Comment

- Created a bunch of interfaces that let us know what is going on.
- Split, updated and zopefied the Logger code.
- Reorganized dir structure in Zope.Server
- HTTP component split up in files (HTTP server works)
- Inserted Shane's skeleton FTP code (since I like his better than mine)
- Took a first cut at the Virtual File System (VFS) by copying and updating
  medusa'a old filesys.py code.



=== Added File Zope3/lib/python/Zope/Server/VFS/IFileSystem.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: IFileSystem.py,v 1.1.2.1 2002/04/02 05:08:07 srichter Exp $
"""

from Interface import Interface

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

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

    def current_directory():
        """Return a string representing the current directory."""
        
    def listdir(path, long=0):
        """Return a listing of the directory at 'path' The empty string
        indicates the current directory.  If 'long' is set, instead
        return a list of (name, stat_info) tuples
        """
        
    def open(path, mode):
        """Return an open file object.
        """
        
    def stat(path):
        """Return the equivalent of os.stat() on the given path.
        """
        
    def isdir(path):
        """Does the path represent a directory?
        """
        
    def isfile(path):
        """Does the path represent a plain file?
        """
        
    def cwd(path):
        """Change the working directory.
        """
        
    def cdup():
        """Change to the parent of the current directory.
        """
        
    def longify(path):
        """Return a 'long' representation of the filename
           [for the output of the LIST command]
        """


=== Added File Zope3/lib/python/Zope/Server/VFS/ListProducer.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: ListProducer.py,v 1.1.2.1 2002/04/02 05:08:07 srichter Exp $
"""
        
class ListProducer:
    """Produces a string, representing a list of files. Note that not all
       files will be displayed at once.
    """
    
    def __init__ (self, file_list, long, longify, batch_size=50):
        self.file_list = file_list
        self.long = long
        self.longify = longify
        self.batch_size = int(batch_size) 
        self.done = 0

        
    def ready(self):
        if len(self.file_list):
            return 1
        else:
            if not self.done:
                self.done = 1
            return 0

        
    def more (self):
        # Check whether we have elements in the first place
        if not self.file_list:
            return ''
        else:
            # Now determine how many files to display
            batch_size = self.batch_size
            if batch_size > len(self.file_list):
                batch_size = len(self.file_list)

            # get the set we want
            batch = self.file_list[:batch_size]

            # Do we want to have fancy long output?
            if self.long:
                batch = map(self.longify, batch)

            # Remove the displayed files from the list.
            self.file_list = self.file_list[self.batch_size:]
            return '\r\n'.join(batch) + '\r\n'
            


=== Added File Zope3/lib/python/Zope/Server/VFS/MSDOSFileSystem.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: MSDOSFileSystem.py,v 1.1.2.1 2002/04/02 05:08:07 srichter Exp $
"""
        
from OSFileSystem import OSFileSystem        
                
class MSDOSFileSystem(OSFileSystem):
    """This is a generic MS-DOS-like FileSystem. It mimics MS-DOS' output.
    """

    __implements__ = OFFileSystem.__implements__


    def longify(self, (path, stat_info)):
        return msdos_longify(path, stat_info)

        

def msdos_longify(file, stat_info):
    """This matches the output of NT's ftp server (when in MSDOS mode)
       exactly.
    """
    if stat.S_ISDIR (stat_info[stat.ST_MODE]):
        dir = '<DIR>'
    else:
        dir = '     '
    date = msdos_date (stat_info[stat.ST_MTIME])
    return '%s       %s %8d %s' % (date, dir, stat_info[stat.ST_SIZE], file)

    
def msdos_date(t):
    try:
        info = time.gmtime(t)
    except:
        info = time.gmtime(0)

    # year, month, day, hour, minute, second, ...
    if info[3] > 11:
        merid = 'PM'
        info[3] = info[3] - 12
    else:
        merid = 'AM'
        
    return '%02d-%02d-%02d  %02d:%02d%s' % (
            info[1], info[2], info[0]%100, info[3], info[4], merid )


=== Added File Zope3/lib/python/Zope/Server/VFS/MergedFileSystem.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: MergedFileSystem.py,v 1.1.2.1 2002/04/02 05:08:07 srichter Exp $
"""        
        
class MergedFileSystem:
    """A merged filesystem will let you plug other filesystems
       together.  We really need the equivalent of a 'mount'
       capability - this seems to be the most general idea.  So you'd
       use a 'mount' method to place another filesystem somewhere in
       the hierarchy.
       
       Note: this is most likely how I will handle ~user directories
       with the http server.
    """

    def __init__ (self, *fsys):
        pass
        


=== 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.2.1 2002/04/02 05:08:07 srichter Exp $
"""
        
import os, re
import stat
import time
        
from IFileSystem import IFileSystem


class OSFileSystem:
    """Generic OS FileSystem implementation. 
    """

    __implements__ = IFileSystem

    path_module = os.path
    
    # set this to zero if you want to disable pathname globbing.
    # [we currently don't glob, anyway]
    do_globbing = 1
    
    def __init__ (self, root, wd='/'):
        self.root = root
        self.wd = wd

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

    def current_directory(self):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        return self.wd


    def listdir(self, path, long=0):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        p = self.translate (path)
        # I think we should glob, but limit it to the current
        # directory only.
        ld = os.listdir(p)
        if not long:
            return list_producer (ld, 0, None)
        else:
            old_dir = os.getcwd()
            try:
                os.chdir (p)
                # if os.stat fails we ignore that file.
                result = filter(None, map(safe_stat, ld))
            finally:
                os.chdir (old_dir)
            return list_producer (result, 1, self.longify)


    def open(self, path, mode):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        p = self.translate (path)
        return open (p, mode)


    # XXX: implement a cache w/timeout for stat()
    def stat(self, path):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        p = self.translate(path)
        return os.stat (p)


    def isdir(self, path):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        p = self.normalize (self.path_module.join (self.wd, path))
        return self.path_module.isdir (self.translate(p))


    def isfile(self, path):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        p = self.normalize (self.path_module.join (self.wd, path))
        return self.path_module.isfile (self.translate(p))


    def cwd(self, path):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        p = self.normalize (self.path_module.join (self.wd, path))
        translated_path = self.translate(p)
        if not self.path_module.isdir (translated_path):
            return 0
        else:
            old_dir = os.getcwd()
            # temporarily change to that directory, in order
            # to see if we have permission to do so.
            try:
                can = 0
                try:
                    os.chdir (translated_path)
                    can = 1
                    self.wd = p
                except:
                    pass
            finally:
                if can:
                    os.chdir (old_dir)
            return can


    def cdup(self):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        return self.cwd('..')


    def longify(self, path):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        return unix_longify (path, stat_info)

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

                
    def unlink (self, path):
        p = self.translate (path)
        return os.unlink (p)
        
    def mkdir (self, path):
        p = self.translate (path)
        return os.mkdir (p)
        
    def rmdir (self, path):
        p = self.translate (path)
        return os.rmdir (p)

        
    # utility methods

    def normalize (self, path):
            # watch for the ever-sneaky '/+' path element
        path = re.sub('/+', '/', path)
        p = self.path_module.normpath (path)
        # remove 'dangling' cdup's.
        if len(p) > 2 and p[:3] == '/..':
            p = '/'
        return p

        
    def translate (self, path):
        """We need to join together three separate path components,
           and do it safely.  <real_root>/<current_directory>/<path>
           use the operating system's path separator.
        """        
        path = os.sep.join('/'.split(path))
        p = self.normalize(self.path_module.join(self.wd, path))
        p = self.normalize(self.path_module.join(self.root, p[1:]))
        return p
        
    def __repr__ (self):
        return '<Unix-Style FS Root:%s CWD:%s>' % (self.root, self.wd)
        
    
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
                  'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

mode_table = {
        '0':'---',
        '1':'--x',
        '2':'-w-',
        '3':'-wx',
        '4':'r--',
        '5':'r-x',
        '6':'rw-',
        '7':'rwx'
        }


def unix_longify (file, stat_info):
        # for now, only pay attention to the lower bits
    mode = ('%o' % stat_info[stat.ST_MODE])[-3:]
    mode = ''.join(map (lambda x: mode_table[x], mode))
    if stat.S_ISDIR (stat_info[stat.ST_MODE]):
        dirchar = 'd'
    else:
        dirchar = '-'
    date = ls_date (long(time.time()), stat_info[stat.ST_MTIME])
    return '%s%s %3d %-8s %-8s %8d %s %s' % (
            dirchar,
            mode,
            stat_info[stat.ST_NLINK],
            stat_info[stat.ST_UID],
            stat_info[stat.ST_GID],
            stat_info[stat.ST_SIZE],
            date,
            file
            )
    
    
def ls_date (now, t):
    """Emulate the unix 'ls' command's date field.  it has two formats
       - if the date is more than 180 days in the past, then it's like
       this: Oct 19 1995 otherwise, it looks like this: Oct 19 17:33
    """
    try:
        info = time.gmtime(t)
    except:
        info = time.gmtime(0)

    # 15,600,000 == 86,400 * 180
    if (now - t) > 15600000:
        return '%s %2d  %d' % (
                months[info[1]-1],
                info[2],
                info[0]
                )
    else:
        return '%s %2d %02d:%02d' % (
                months[info[1]-1],
                info[2],
                info[3],
                info[4]
                )


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


=== Added File Zope3/lib/python/Zope/Server/VFS/UnixFileSystem.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: UnixFileSystem.py,v 1.1.2.1 2002/04/02 05:08:07 srichter Exp $
"""
        
import os
from OSFileSystem import OSFileSystem

class UnixFileSystem(OSFileSystem):
    """Generic Unix File System."""

    __implements__ = OFFileSystem.__implements__


    
class SchizophrenicUnixFileSystem(OSFileSystem):
    """This File System always wants to be called with a specific user in mind.
    """

    __implements__ = OFFileSystem.__implements__


    # Get process information
    PROCESS_UID		= os.getuid()
    PROCESS_EUID	= os.geteuid()
    PROCESS_GID		= os.getgid()
    PROCESS_EGID	= os.getegid()

    
    def __init__ (self, root, wd='/', persona=(None, None)):
        super(SchizophrenicUnixFileSystem, self).__init__(root, wd)
        self.persona = persona

        
    def become_persona (self):
        if self.persona is not (None, None):
            uid, gid = self.persona
            # the order of these is important!
            os.setegid(gid)
            os.seteuid(uid)

            
    def become_nobody (self):
        if self.persona is not (None, None):
            os.seteuid(self.PROCESS_UID)
            os.setegid(self.PROCESS_GID)
            

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

    def cwd (self, path):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        try:
            self.become_persona()
            return super(SchizophrenicUnixFileSystem, self).cwd(path)
        finally:
            self.become_nobody()

            
    def cdup (self, path):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        try:
            self.become_persona()
            return super(SchizophrenicUnixFileSystem, self).cdup()
        finally:
            self.become_nobody()

            
    def open (self, filename, mode):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        try:
            self.become_persona()
            return super(SchizophrenicUnixFileSystem, self).open(filename,
                                                                 mode)
        finally:
            self.become_nobody()

            
    def listdir (self, path, long=0):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        try:
            self.become_persona()
            return super(SchizophrenicUnixFileSystem, self).listdir(path, long)
        finally:
            self.become_nobody()

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


=== Added File Zope3/lib/python/Zope/Server/VFS/ZODBFileSystem.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: ZODBFileSystem.py,v 1.1.2.1 2002/04/02 05:08:07 srichter Exp $
"""
        
import os, re
import stat
import time
        
from IFileSystem import IFileSystem
from ListProducer import ListProducer
from Zope.App.Traversing.ITraverser import ITraverser
from Zope.ComponentArchitecture import getAdapter
from Zope.App.OFS.Container.IContainer import IContainer
from Zope.ContextWrapper import wrapper


class ZODBFileSystem:
    """Generic OS FileSystem implementation. 
    """

    __implements__ = IFileSystem

    def __init__ (self, publication, init_path='/'):
        self._publication = publication
        self._current = publication.traverse(init_path)

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

    def current_directory(self):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        traverser = getAdapter(self._current, ITraverser)
        return '/' + '/'.join(traverser.getPhysicalPath())


    def listdir(self, path, long=0):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        path = self.translate(path)
        object = self._publication.traverse(path)

        # XXX: Should check whether object is a Container

        if not long:
            list = object.objectIds()
            return ListProducer(list, 0, None)
        else:
            list = object.objectItems()
            return ListProducer(result, 1, self.longify)


    def open(self, path, mode):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        p = self.translate (path)
        return open (p, mode)


    def stat(self, path):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        p = self.translate(path)
        object = self._publication.traverse(path)
        return object


    def isdir(self, path):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        path = self.normalize('/'.join (self.current_directory(), path))
        object = self._publication.traverse(path)
        return IContainer.isImplementedBy(object)


    def isfile(self, path):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        path = self.normalize('/'.join (self.current_directory(), path))
        object = self._publication.traverse(path)
        return not IContainer.isImplementedBy(object)


    def cwd(self, path):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        path = self.normalize('/'.join (self.wd, path))
        path = self.translate(path)
        try:
            self._current = self._publication.traverse(path)
            return 1
        except:
            return 0


    def cdup(self):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'

        parent = wrapper.getContext(self._current)

        if parent is not None:
            self._current = parent
            return 1
        else:
            return 0


    def longify(self, object):
        'See Zope.Server.VFS.IFileSystem.IFileSystem'
        return unix_longify (path, stat_info)

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

                
    def unlink (self, path):
        """ """
        pass

        
    def mkdir (self, path):
        """ """
        pass

        
    def rmdir (self, path):
        """ """
        pass

        
    # utility methods

    def normalize (self, path):
            # watch for the ever-sneaky '/+' path element
        path = re.sub('/+', '/', path)
        p = self.path_module.normpath (path)
        # remove 'dangling' cdup's.
        if len(p) > 2 and p[:3] == '/..':
            p = '/'
        return p

        
    def translate (self, path):
        """We need to join together three separate path components,
           and do it safely.  <real_root>/<current_directory>/<path>
           use the operating system's path separator.
        """        
        path = os.sep.join('/'.split(path))
        p = self.normalize(self.path_module.join(self.wd, path))
        p = self.normalize(self.path_module.join(self.root, p[1:]))
        return p
        
    def __repr__ (self):
        return '<Unix-Style FS Root:%s CWD:%s>' % (self.root, self.wd)
        
    
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
                  'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']

mode_table = {
        '0':'---',
        '1':'--x',
        '2':'-w-',
        '3':'-wx',
        '4':'r--',
        '5':'r-x',
        '6':'rw-',
        '7':'rwx'
        }


def unix_longify (file, stat_info):
        # for now, only pay attention to the lower bits
    mode = ('%o' % stat_info[stat.ST_MODE])[-3:]
    mode = ''.join(map (lambda x: mode_table[x], mode))
    if stat.S_ISDIR (stat_info[stat.ST_MODE]):
        dirchar = 'd'
    else:
        dirchar = '-'
    date = ls_date (long(time.time()), stat_info[stat.ST_MTIME])
    return '%s%s %3d %-8s %-8s %8d %s %s' % (
            dirchar,
            mode,
            stat_info[stat.ST_NLINK],
            stat_info[stat.ST_UID],
            stat_info[stat.ST_GID],
            stat_info[stat.ST_SIZE],
            date,
            file
            )
    
    
def ls_date (now, t):
    """Emulate the unix 'ls' command's date field.  it has two formats
       - if the date is more than 180 days in the past, then it's like
       this: Oct 19 1995 otherwise, it looks like this: Oct 19 17:33
    """
    try:
        info = time.gmtime(t)
    except:
        info = time.gmtime(0)

    # 15,600,000 == 86,400 * 180
    if (now - t) > 15600000:
        return '%s %2d  %d' % (
                months[info[1]-1],
                info[2],
                info[0]
                )
    else:
        return '%s %2d %02d:%02d' % (
                months[info[1]-1],
                info[2],
                info[3],
                info[4]
                )


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


=== 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.2.1 2002/04/02 05:08:07 srichter Exp $
"""