merge tls-sprint
authorsylvain.thenault@logilab.fr
Tue, 28 Apr 2009 19:12:52 +0200
branchtls-sprint
changeset 1521 973c5f1dfad4
parent 1519 5cfc5cc1dd20 (diff)
parent 1520 b097057e629d (current diff)
child 1522 47b2ffbee760
merge
cwconfig.py
--- a/__init__.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/__init__.py	Tue Apr 28 19:12:52 2009 +0200
@@ -74,7 +74,7 @@
             encoding = 'utf-8'
         self.encoding = encoding
         # cache result of execution for (rql expr / eids),
-        # should be emptied on commit/rollback of the server session / web 
+        # should be emptied on commit/rollback of the server session / web
         # connection
         self.local_perm_cache = {}
 
@@ -82,7 +82,7 @@
         if self.user:
             return self.user.property_value(key)
         return self.vreg.property_value(key)
-    
+
     def etype_rset(self, etype, size=1):
         """return a fake result set for a particular entity type"""
         from cubicweb.rset import ResultSet
@@ -114,7 +114,7 @@
             return None
 
     # url generation methods ##################################################
-    
+
     def build_url(self, method, base_url=None, **kwargs):
         """return an absolute URL using params dictionary key/values as URL
         parameters. Values are automatically URL quoted, and the
@@ -130,7 +130,7 @@
         if not kwargs:
             return u'%s%s' % (base_url, path)
         return u'%s%s?%s' % (base_url, path, self.build_url_params(**kwargs))
-        
+
 
     def build_url_params(self, **kwargs):
         """return encoded params to incorporate them in an URL"""
@@ -154,7 +154,7 @@
 
     def url_unquote(self, quoted):
         """returns a unicode unquoted string
-        
+
         decoding is based on `self.encoding` which is the encoding
         used in `url_quote`
         """
@@ -164,10 +164,10 @@
             return unicode(urlunquote(quoted), self.encoding)
         except UnicodeDecodeError: # might occurs on manually typed URLs
             return unicode(urlunquote(quoted), 'iso-8859-1')
-    
+
 
     # session's user related methods #####################################
-    
+
     @cached
     def user_data(self):
         """returns a dictionnary with this user's information"""
@@ -197,21 +197,21 @@
         return False
 
     # abstract methods to override according to the web front-end #############
-    
+
     def base_url(self):
         """return the root url of the application"""
         raise NotImplementedError
-    
+
     def decorate_rset(self, rset):
         """add vreg/req (at least) attributes to the given result set """
         raise NotImplementedError
-    
+
     def describe(self, eid):
         """return a tuple (type, sourceuri, extid) for the entity with id <eid>"""
         raise NotImplementedError
-        
+
 
-# XXX 2.45 is allowing nicer entity type names, use this map for bw compat    
+# XXX 2.45 is allowing nicer entity type names, use this map for bw compat
 ETYPE_NAME_MAP = {# 3.2 migration
                   'ECache': 'CWCache',
                   'EUser': 'CWUser',
@@ -268,7 +268,7 @@
                     'ezone': 'zone',
                     'i18ncontent': 'i18ncontent',
                     'svnfile': 'vcsfile',
-                    
+
                     'eclassschemes': 'keyword',
                     'eclassfolders': 'folder',
                     'eclasstags': 'tag',
@@ -300,4 +300,4 @@
         return obj.target
     except AttributeError:
         return neg_role(obj.role)
-        
+
--- a/cwconfig.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/cwconfig.py	Tue Apr 28 19:12:52 2009 +0200
@@ -4,6 +4,11 @@
 :organization: Logilab
 :copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+
+.. envvar:: CW_CUBES_PATH
+
+   Augments the default search path for cubes
+   
 """
 __docformat__ = "restructuredtext en"
 
--- a/cwvreg.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/cwvreg.py	Tue Apr 28 19:12:52 2009 +0200
@@ -117,25 +117,24 @@
             clear_cache(self, 'etype_class')
             # we may want to keep interface dependent objects (e.g.for i18n
             # catalog generation)
-            if not self.config.cleanup_interface_sobjects:
-                return
-            # remove vobjects that don't support any available interface
-            implemented_interfaces = set()
-            for etype in self.schema.entities():
-                cls = self.etype_class(etype)
-                for iface in cls.__implements__:
-                    implemented_interfaces.update(iface.__mro__)
-                implemented_interfaces.update(cls.__mro__)
-            for obj, ifaces in self._needs_iface.items():
-                ifaces = frozenset(isinstance(iface, basestring)
-                                   and iface in self.schema
-                                   and self.etype_class(iface)
-                                   or iface
-                                   for iface in ifaces)
-                if not ('Any' in ifaces or ifaces & implemented_interfaces):
-                    self.debug('kicking vobject %s (no implemented interface '
-                               'among %s)', obj, ifaces)
-                    self.unregister(obj)
+            if self.config.cleanup_interface_sobjects:
+                # remove vobjects that don't support any available interface
+                implemented_interfaces = set()
+                for etype in self.schema.entities():
+                    cls = self.etype_class(etype)
+                    for iface in cls.__implements__:
+                        implemented_interfaces.update(iface.__mro__)
+                    implemented_interfaces.update(cls.__mro__)
+                for obj, ifaces in self._needs_iface.items():
+                    ifaces = frozenset(isinstance(iface, basestring)
+                                       and iface in self.schema
+                                       and self.etype_class(iface)
+                                       or iface
+                                       for iface in ifaces)
+                    if not ('Any' in ifaces or ifaces & implemented_interfaces):
+                        self.debug('kicking vobject %s (no implemented '
+                                   'interface among %s)', obj, ifaces)
+                        self.unregister(obj)
             # clear needs_iface so we don't try to remove some not-anymore-in
             # objects on automatic reloading
             self._needs_iface.clear()
--- a/devtools/apptest.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/devtools/apptest.py	Tue Apr 28 19:12:52 2009 +0200
@@ -32,11 +32,11 @@
     @property
     def message(self):
         return message_from_string(self.msg)
-    
+
     def __repr__(self):
         return '<Email to %s with subject %s>' % (','.join(self.recipients),
                                                   self.message.get('Subject'))
-    
+
 class MockSMTP:
     def __init__(self, server, port):
         pass
@@ -100,7 +100,7 @@
     env = None
     configcls = ApptestConfiguration
     requestcls = FakeRequest
-    
+
     # user / session management ###############################################
 
     def user(self, req=None):
@@ -118,13 +118,13 @@
 
     def restore_connection(self):
         self.env.restore_connection()
-        
+
     # db api ##################################################################
 
     @nocoverage
     def cursor(self, req=None):
         return self.env.cnx.cursor(req or self.request())
-    
+
     @nocoverage
     def execute(self, *args, **kwargs):
         return self.env.execute(*args, **kwargs)
@@ -132,19 +132,19 @@
     @nocoverage
     def commit(self):
         self.env.cnx.commit()
-    
+
     @nocoverage
     def rollback(self):
         try:
             self.env.cnx.rollback()
         except ProgrammingError:
             pass
-        
+
     # other utilities #########################################################
     def set_debug(self, debugmode):
         from cubicweb.server import set_debug
         set_debug(debugmode)
-    
+
     @property
     def config(self):
         return self.vreg.config
@@ -152,7 +152,7 @@
     def session(self):
         """return current server side session (using default manager account)"""
         return self.env.repo._sessions[self.env.cnx.sessionid]
-    
+
     def request(self, *args, **kwargs):
         """return a web interface request"""
         return self.env.create_request(*args, **kwargs)
@@ -160,16 +160,16 @@
     @nocoverage
     def rset_and_req(self, *args, **kwargs):
         return self.env.get_rset_and_req(*args, **kwargs)
-    
+
     def entity(self, rql, args=None, eidkey=None, req=None):
         return self.execute(rql, args, eidkey, req=req).get_entity(0, 0)
-    
+
     def etype_instance(self, etype, req=None):
         req = req or self.request()
         e = self.env.vreg.etype_class(etype)(req, None, None)
         e.eid = None
         return e
-    
+
     def add_entity(self, etype, **kwargs):
         rql = ['INSERT %s X' % etype]
 
@@ -185,15 +185,15 @@
             sub_rql = []
             for key, value in kwargs.iteritems():
                 # entities
-                if hasattr(value, 'eid'): 
+                if hasattr(value, 'eid'):
                     new_value = "%s__" % key.upper()
-                    
+
                     entities[new_value] = value.eid
                     rql_args[new_value] = value.eid
-                    
+
                     sub_rql.append("X %s %s" % (key, new_value))
                 # final attributes
-                else: 
+                else:
                     sub_rql.append('X %s %%(%s)s' % (key, key))
                     rql_args[key] = value
             rql.append(', '.join(sub_rql))
@@ -215,8 +215,8 @@
         self.vreg.config.global_set_option(optname, value)
 
     def pviews(self, req, rset):
-        return sorted((a.id, a.__class__) for a in self.vreg.possible_views(req, rset)) 
-        
+        return sorted((a.id, a.__class__) for a in self.vreg.possible_views(req, rset))
+
     def pactions(self, req, rset, skipcategories=('addrelated', 'siteactions', 'useractions')):
         return [(a.id, a.__class__) for a in self.vreg.possible_vobjects('actions', req, rset)
                 if a.category not in skipcategories]
@@ -224,7 +224,7 @@
     def pactions_by_cats(self, req, rset, categories=('addrelated',)):
         return [(a.id, a.__class__) for a in self.vreg.possible_vobjects('actions', req, rset)
                 if a.category in categories]
-    
+
     paddrelactions = deprecated_function(pactions_by_cats)
 
     def pactionsdict(self, req, rset, skipcategories=('addrelated', 'siteactions', 'useractions')):
@@ -234,7 +234,7 @@
                 res.setdefault(a.category, []).append(a.__class__)
         return res
 
-    
+
     def remote_call(self, fname, *args):
         """remote call simulation"""
         dump = simplejson.dumps
@@ -244,7 +244,7 @@
         return ctrl.publish(), req
 
     # default test setup and teardown #########################################
-        
+
     def setup_database(self):
         pass
 
@@ -264,7 +264,7 @@
         self.setup_database()
         self.commit()
         MAILBOX[:] = [] # reset mailbox
-        
+
     @nocoverage
     def tearDown(self):
         self.rollback()
@@ -355,7 +355,7 @@
     """
     __metaclass__ = autorepo
     repo_config = None # set a particular config instance if necessary
-    
+
     # user / session management ###############################################
 
     def create_user(self, user, groups=('users',), password=None, commit=True):
@@ -369,9 +369,9 @@
                       {'x': eid})
         if commit:
             self.commit()
-        self.session.reset_pool()        
+        self.session.reset_pool()
         return eid
-    
+
     def login(self, login, password=None):
         cnx = repo_connect(self.repo, unicode(login), password or login,
                            ConnectionProperties('inmemory'))
@@ -380,7 +380,7 @@
 
     def current_session(self):
         return self.repo._sessions[self.cnxs[-1].sessionid]
-    
+
     def restore_connection(self):
         assert len(self.cnxs) == 1, self.cnxs
         cnx = self.cnxs.pop()
@@ -388,7 +388,7 @@
             cnx.close()
         except Exception, ex:
             print "exception occured while closing connection", ex
-        
+
     # db api ##################################################################
 
     def execute(self, rql, args=None, eid_key=None):
@@ -400,27 +400,27 @@
         # application entities for convenience
         self.session.set_pool()
         return rset
-    
+
     def commit(self):
         self.__commit(self.cnxid)
-        self.session.set_pool()        
-    
+        self.session.set_pool()
+
     def rollback(self):
         self.__rollback(self.cnxid)
-        self.session.set_pool()        
-    
+        self.session.set_pool()
+
     def close(self):
         self.__close(self.cnxid)
 
     # other utilities #########################################################
-    
+
     def set_debug(self, debugmode):
         from cubicweb.server import set_debug
         set_debug(debugmode)
-        
+
     def set_option(self, optname, value):
         self.vreg.config.global_set_option(optname, value)
-            
+
     def add_entity(self, etype, **kwargs):
         restrictions = ', '.join('X %s %%(%s)s' % (key, key) for key in kwargs)
         rql = 'INSERT %s X' % etype
@@ -434,7 +434,7 @@
         user = unicode(config.sources()['system']['db-user'])
         passwd = config.sources()['system']['db-password']
         return user, passwd
-    
+
     def close_connections(self):
         for cnx in self.cnxs:
             try:
@@ -446,10 +446,10 @@
 
     pactions = EnvBasedTC.pactions.im_func
     pactionsdict = EnvBasedTC.pactionsdict.im_func
-    
+
     # default test setup and teardown #########################################
     copy_schema = False
-    
+
     def _prepare(self):
         MAILBOX[:] = [] # reset mailbox
         if hasattr(self, 'cnxid'):
@@ -494,15 +494,15 @@
     @property
     def schema(self):
         return self.repo.schema
-    
+
     def setUp(self):
         self._prepare()
         self.session.set_pool()
         self.maxeid = self.session.system_sql('SELECT MAX(eid) FROM entities').fetchone()[0]
-        
+
     def tearDown(self):
         self.close_connections()
         self.rollback()
         self.session.unsafe_execute('DELETE Any X WHERE X eid > %(x)s', {'x': self.maxeid})
         self.commit()
-    
+
--- a/devtools/devctl.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/devtools/devctl.py	Tue Apr 28 19:12:52 2009 +0200
@@ -93,8 +93,8 @@
         config = DevCubeConfiguration(cube)
         schema = config.load_schema()
     else:
+        config = libconfig
         schema = config.load_schema()
-        config = libconfig
         libconfig = None
     vreg = CubicWebRegistry(config)
     # set_schema triggers objects registrations
@@ -130,7 +130,7 @@
     w('# subject and object forms for each relation type\n')
     w('# (no object form for final relation types)\n')
     w('\n')
-    if libschema is not None:
+    if libconfig is not None:
         relations = [r for r in schema.relations() if not r in libschema]
     else:
         relations = schema.relations()
@@ -155,9 +155,13 @@
                 if rschema.is_final():
                     continue
                 for teschema in rschema.targets(eschema, role):
-                    if defined_in_library(libschema, eschema, rschema,
-                                          teschema, role):
-                        continue
+                    if libconfig is not None:
+                        if role == 'subject':
+                            subjtype, objtype = etype, tetype
+                        else:
+                            subjtype, objtype = tetype, etype
+                        if libschema.rschema(rtype).has_rdef(subjtype, objtype):
+                            continue
                     if actionbox.relation_mode(rschema, eschema, teschema, role) == 'create':
                         if role == 'subject':
                             label = 'add %s %s %s %s' % (eschema, rschema,
@@ -179,7 +183,6 @@
         libvreg.set_schema(libschema) # trigger objects registration
         # prefill done set
         list(_iter_vreg_objids(libvreg, done))
-    print 'done', done
     for objid in _iter_vreg_objids(vreg, done):
         add_msg(w, '%s_description' % objid)
         add_msg(w, objid)
@@ -197,7 +200,7 @@
                     break
 
 
-def defined_in_library(libschema, etype, rtype, tetype, role):
+def defined_in_library(etype, rtype, tetype, role):
     """return true if the given relation definition exists in cubicweb's library
     """
     if libschema is None:
@@ -271,8 +274,12 @@
             cmd = 'xgettext --no-location --omit-header -k_ -o %s %s'
             if lang is not None:
                 cmd += ' -L %s' % lang
-            potfiles.append(join(tempdir, '%s.pot' % id))
-            execute(cmd % (potfiles[-1], ' '.join(files)))
+            potfile = join(tempdir, '%s.pot' % id)
+            execute(cmd % (potfile, ' '.join(files)))
+            if exists(potfile):
+                potfiles.append(potfile)
+            else:
+                print 'WARNING: %s file not generated' % potfile
         print '******** merging .pot files'
         cubicwebpot = join(tempdir, 'cubicweb.pot')
         execute('msgcat %s > %s' % (' '.join(potfiles), cubicwebpot))
--- a/devtools/fake.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/devtools/fake.py	Tue Apr 28 19:12:52 2009 +0200
@@ -24,13 +24,13 @@
         self.apphome = apphome
         self._cubes = cubes
         self['auth-mode'] = 'cookie'
-        self['uid'] = None 
+        self['uid'] = None
         self['base-url'] = BASE_URL
         self['rql-cache-size'] = 100
-       
+
     def cubes(self, expand=False):
         return self._cubes
-    
+
     def sources(self):
         return {}
 
@@ -41,7 +41,7 @@
         self.properties = {'ui.encoding': 'UTF8',
                            'ui.language': 'en',
                            }
-        
+
     def property_value(self, key):
         return self.properties[key]
 
@@ -51,10 +51,10 @@
         'views' : [Mock(id='primary'), Mock(id='secondary'),
                          Mock(id='oneline'), Mock(id='list')],
         }
-    
+
     def registry_objects(self, name, oid=None):
         return self._registries[name]
-    
+
     def etype_class(self, etype):
         class Entity(dict):
             e_schema = self.schema[etype]
@@ -112,15 +112,15 @@
     def set_header(self, header, value):
         """set an output HTTP header"""
         pass
-    
+
     def add_header(self, header, value):
         """set an output HTTP header"""
         pass
-    
+
     def remove_header(self, header):
         """remove an output HTTP header"""
         pass
-    
+
     def get_header(self, header, default=None):
         """return the value associated with the given input header,
         raise KeyError if the header is not set
@@ -169,7 +169,7 @@
         self.is_internal_session = False
         self.is_super_session = self.user.eid == -1
         self._query_data = {}
-        
+
     def execute(self, *args):
         pass
     def commit(self, *args):
@@ -186,7 +186,7 @@
 
     def set_entity_cache(self, entity):
         pass
-    
+
 class FakeRepo(object):
     querier = None
     def __init__(self, schema, vreg=None, config=None):
@@ -199,8 +199,9 @@
 
     def internal_session(self):
         return FakeSession(self)
-    
-    def extid2eid(self, source, extid, etype, session, insert=True):
+
+    def extid2eid(self, source, extid, etype, session, insert=True,
+                  recreate=False):
         try:
             return self.extids[extid]
         except KeyError:
@@ -213,7 +214,7 @@
             self.eids[eid] = extid
             source.after_entity_insertion(session, extid, entity)
             return eid
-        
+
     def eid2extid(self, source, eid, session=None):
         return self.eids[eid]
 
@@ -228,7 +229,7 @@
     def __init__(self, uri):
         self.uri = uri
 
-        
+
 class FakePool(object):
     def source(self, uri):
         return FakeSource(uri)
--- a/devtools/htmlparser.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/devtools/htmlparser.py	Tue Apr 28 19:12:52 2009 +0200
@@ -5,11 +5,13 @@
 from lxml import etree
 
 from cubicweb.view import STRICT_DOCTYPE, TRANSITIONAL_DOCTYPE
+STRICT_DOCTYPE = str(STRICT_DOCTYPE)
+TRANSITIONAL_DOCTYPE = str(TRANSITIONAL_DOCTYPE)
 
 ERR_COUNT = 0
 
 class Validator(object):
-    
+
     def parse_string(self, data, sysid=None):
         try:
             data = self.preprocess_data(data)
@@ -32,10 +34,10 @@
 
     def preprocess_data(self, data):
         """used to fix potential blockquote mess generated by docutils"""
-        if str(STRICT_DOCTYPE) not in data:
+        if STRICT_DOCTYPE not in data:
             return data
         # parse using transitional DTD
-        data = data.replace(str(STRICT_DOCTYPE), str(TRANSITIONAL_DOCTYPE))
+        data = data.replace(STRICT_DOCTYPE, TRANSITIONAL_DOCTYPE)
         tree = etree.fromstring(data, self.parser)
         namespace = tree.nsmap.get(None)
         # this is the list of authorized child tags for <blockquote> nodes
@@ -51,9 +53,10 @@
             parent = blockquote.getparent()
             parent.remove(blockquote)
         data = etree.tostring(tree)
-        return '<?xml version="1.0" encoding="UTF-8"?>%s\n%s' % (str(STRICT_DOCTYPE), data)
+        return '<?xml version="1.0" encoding="UTF-8"?>%s\n%s' % (
+            STRICT_DOCTYPE, data)
 
-   
+
 class SaxOnlyValidator(Validator):
 
     def __init__(self):
@@ -66,7 +69,7 @@
         Validator.__init__(self)
         self.parser = etree.HTMLParser()
 
-    
+
 
 class PageInfo(object):
     """holds various informations on the view's output"""
@@ -84,7 +87,7 @@
         self.h4_tags = self.find_tag('h4')
         self.input_tags = self.find_tag('input')
         self.title_tags = [self.h1_tags, self.h2_tags, self.h3_tags, self.h4_tags]
-        
+
     def find_tag(self, tag):
         """return a list which contains text of all "tag" elements """
         if self.default_ns is None:
@@ -94,14 +97,14 @@
         if tag in ('a', 'input'):
             return [(elt.text, elt.attrib) for elt in self.etree.iterfind(iterstr)]
         return [u''.join(elt.xpath('.//text()')) for elt in self.etree.iterfind(iterstr)]
-         
+
     def appears(self, text):
         """returns True if <text> appears in the page"""
         return text in self.raw_text
 
     def __contains__(self, text):
         return text in self.source
-    
+
     def has_title(self, text, level=None):
         """returns True if <h?>text</h?>
 
@@ -131,7 +134,7 @@
                 if sre.match(title):
                     return True
             return False
-    
+
     def has_link(self, text, url=None):
         """returns True if <a href=url>text</a> was found in the page"""
         for link_text, attrs in self.a_tags:
@@ -145,7 +148,7 @@
                 except KeyError:
                     continue
         return False
-    
+
     def has_link_regexp(self, pattern, url=None):
         """returns True if <a href=url>pattern</a> was found in the page"""
         sre = re.compile(pattern)
--- a/embedded/mx/DateTime/ARPA.py	Tue Apr 28 13:28:37 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,227 +0,0 @@
-""" This module provides a set of constructors and routines to convert
-    between DateTime[Delta] instances and ARPA representations of date
-    and time. The format is specified by RFC822 + RFC1123.
-
-    Note: Timezones are only interpreted by ParseDateTimeGMT(). All
-    other constructors silently ignore the time zone information.
-
-    Copyright (c) 1998-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
-    Copyright (c) 2000-2007, eGenix.com Software GmbH; mailto:info@egenix.com
-    See the documentation for further information on copyrights,
-    or contact the author. All Rights Reserved.
-
-"""
-import DateTime,Timezone
-import re,string
-
-# Grammar: RFC822 + RFC1123 + depreciated RFC850
-_litday = '(?P<litday>Mon|Tue|Wed|Thu|Fri|Sat|Sun)[a-z]*'
-_litmonth = '(?P<litmonth>Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)'\
-            '[a-z]*'
-_date = ('(?:(?P<day>\d?\d)(?: +' + _litmonth + 
-         ' +|-(?P<month>\d?\d)-)(?P<year>(?:\d\d)?\d\d))')
-_zone = Timezone.zone
-_time = ('(?:(?P<hour>\d\d):(?P<minute>\d\d)'
-         '(?::(?P<second>\d\d))?(?: +'+_zone+')?)')
-#       Timezone information is made optional because some mail apps
-#       forget to add it (most of these seem to be spamming engines, btw).
-#       It defaults to UTC.
-
-_arpadate = '(?:'+ _litday + ',? )? *' + _date
-_arpadatetime = '(?:'+ _litday + ',? )? *' + _date + ' +' + _time
-
-#       We are not strict about the extra characters: some applications
-#       add extra information to the date header field. Additional spaces
-#       between the fields and extra characters in the literal day
-#       and month fields are also silently ignored.
-
-arpadateRE = re.compile(_arpadate)
-arpadatetimeRE = re.compile(_arpadatetime)
-
-# Translation tables
-litdaytable = {'mon':0, 'tue':1, 'wed':2, 'thu':3, 'fri':4, 'sat':5, 'sun':6 }
-litmonthtable = {'jan':1, 'feb':2, 'mar':3, 'apr':4, 'may':5, 'jun':6,
-                 'jul':7, 'aug':8, 'sep':9, 'oct':10, 'nov':11, 'dec':12 }
-_days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
-_months = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
-                 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]
-
-def ParseDate(arpastring,parse_arpadate=arpadateRE.match,
-
-              strip=string.strip,atoi=string.atoi,atof=string.atof,
-              lower=string.lower):
-
-    """ParseDate(arpastring)
-
-       Returns a DateTime instance reflecting the given ARPA
-       date. Only the date part is parsed, any time part will be
-       ignored. The instance's time is set to 0:00:00.
-
-    """
-    s = strip(arpastring)
-    date = parse_arpadate(s)
-    if not date:
-        raise ValueError,'wrong format'
-    litday,day,litmonth,month,year = date.groups()
-    if len(year) == 2:
-        year = DateTime.add_century(atoi(year))
-    else:
-        year = atoi(year)
-    if litmonth:
-        litmonth = lower(litmonth)
-        try:
-            month = litmonthtable[litmonth]
-        except KeyError:
-            raise ValueError,'wrong month format'
-    else:
-        month = atoi(month)
-    day = atoi(day)
-    # litday and timezone are ignored
-    return DateTime.DateTime(year,month,day)
-
-def ParseDateTime(arpastring,parse_arpadatetime=arpadatetimeRE.match,
-
-                  strip=string.strip,atoi=string.atoi,atof=string.atof,
-                  lower=string.lower):
-
-    """ParseDateTime(arpastring)
-
-       Returns a DateTime instance reflecting the given ARPA date assuming
-       it is local time (timezones are silently ignored).
-    """
-    s = strip(arpastring)
-    date = parse_arpadatetime(s)
-    if not date:
-        raise ValueError,'wrong format or unknown time zone'
-    litday,day,litmonth,month,year,hour,minute,second,zone = date.groups()
-    if len(year) == 2:
-        year = DateTime.add_century(atoi(year))
-    else:
-        year = atoi(year)
-    if litmonth:
-        litmonth = lower(litmonth)
-        try:
-            month = litmonthtable[litmonth]
-        except KeyError:
-            raise ValueError,'wrong month format'
-    else:
-        month = atoi(month)
-    day = atoi(day)
-    hour = atoi(hour)
-    minute = atoi(minute)
-    if second is None:
-        second = 0.0
-    else:
-        second = atof(second)
-    # litday and timezone are ignored
-    return DateTime.DateTime(year,month,day,hour,minute,second)
-
-def ParseDateTimeGMT(arpastring,parse_arpadatetime=arpadatetimeRE.match,
-
-                     strip=string.strip,atoi=string.atoi,atof=string.atof,
-                     lower=string.lower):
-
-    """ParseDateTimeGMT(arpastring)
-
-       Returns a DateTime instance reflecting the given ARPA date converting
-       it to UTC (timezones are honored).
-    """
-    s = strip(arpastring)
-    date = parse_arpadatetime(s)
-    if not date:
-        raise ValueError,'wrong format or unknown time zone'
-    litday,day,litmonth,month,year,hour,minute,second,zone = date.groups()
-    if len(year) == 2:
-        year = DateTime.add_century(atoi(year))
-    else:
-        year = atoi(year)
-    if litmonth:
-        litmonth = lower(litmonth)
-        try:
-            month = litmonthtable[litmonth]
-        except KeyError:
-            raise ValueError,'wrong month format'
-    else:
-        month = atoi(month)
-    day = atoi(day)
-    hour = atoi(hour)
-    minute = atoi(minute)
-    if second is None:
-        second = 0.0
-    else:
-        second = atof(second)
-    offset = Timezone.utc_offset(zone)
-    # litday is ignored
-    return DateTime.DateTime(year,month,day,hour,minute,second) - offset
-
-# Alias
-ParseDateTimeUTC = ParseDateTimeGMT
-
-def str(datetime,tz=None):
-
-    """str(datetime,tz=DateTime.tz_offset(datetime))
-
-    Returns the datetime instance as ARPA date string. tz can be given
-    as DateTimeDelta instance providing the time zone difference from
-    datetime's zone to UTC. It defaults to
-    DateTime.tz_offset(datetime) which assumes local time. """
-
-    if tz is None:
-        tz = datetime.gmtoffset()
-    return '%s, %02i %s %04i %02i:%02i:%02i %+03i%02i' % (
-        _days[datetime.day_of_week], datetime.day, 
-        _months[datetime.month], datetime.year,
-        datetime.hour, datetime.minute, datetime.second,
-        tz.hour,tz.minute)
-
-def strGMT(datetime):
-
-    """ strGMT(datetime)
-
-    Returns the datetime instance as ARPA date string assuming it
-    is given in GMT. """
-
-    return '%s, %02i %s %04i %02i:%02i:%02i GMT' % (
-        _days[datetime.day_of_week], datetime.day, 
-        _months[datetime.month], datetime.year,
-        datetime.hour, datetime.minute, datetime.second)
-
-def strUTC(datetime):
-
-    """ strUTC(datetime)
-
-    Returns the datetime instance as ARPA date string assuming it
-    is given in UTC. """
-
-    return '%s, %02i %s %04i %02i:%02i:%02i UTC' % (
-        _days[datetime.day_of_week], datetime.day, 
-        _months[datetime.month], datetime.year,
-        datetime.hour, datetime.minute, datetime.second)
-
-def _test():
-    import sys, os, rfc822
-    file = os.path.join(os.environ['HOME'], 'nsmail/Inbox')
-    f = open(file, 'r')
-    while 1:
-        m = rfc822.Message(f)
-        if not m:
-            break
-        print 'From:', m.getaddr('from')
-        print 'To:', m.getaddrlist('to')
-        print 'Subject:', m.getheader('subject')
-        raw = m.getheader('date')
-        try:
-            date = ParseDateTimeUTC(raw)
-            print 'Date:',strUTC(date)
-        except ValueError,why:
-            print 'PROBLEMS:',repr(raw),'-->',why
-            raw_input('...hit return to continue')
-        print
-        # Netscape mail file
-        while 1:
-            line = f.readline()
-            if line[:6] == 'From -':
-                break
-
-if __name__ == '__main__':
-    _test()
--- a/embedded/mx/DateTime/DateTime.py	Tue Apr 28 13:28:37 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1054 +0,0 @@
-""" Python part of the low-level DateTime[Delta] type implementation.
-
-    Copyright (c) 1998-2001, Marc-Andre Lemburg; mailto:mal@lemburg.com
-    Copyright (c) 2000-2007, eGenix.com Software GmbH; mailto:info@egenix.com
-    See the documentation for further information on copyrights,
-    or contact the author. All Rights Reserved.
-"""
-# Import the python implementation module
-from mxDateTime_python import *
-from mxDateTime_python import __version__
-
-# Singletons
-oneSecond = DateTimeDelta(0,0,0,1)
-oneMinute = DateTimeDelta(0,0,1)
-oneHour = DateTimeDelta(0,1)
-oneDay = DateTimeDelta(1)
-oneWeek = DateTimeDelta(7)
-Epoch = DateTimeFromAbsDateTime(1,0)
-
-# Shortcuts for pickle; for backward compatibility only (they are now
-# defined in __init__.py to further reduce the pickles length)
-def _DT(absdate,abstime):
-    return DateTimeFromAbsDateTime(absdate,abstime)
-def _DTD(seconds):
-    return DateTimeDeltaFromSeconds(seconds)
-
-# Module init
-class modinit:
-
-    global _time,_string,_math,_types
-    import time,string,math,types
-    _time = time
-    _string = string
-    _math = math
-    _types = types
-
-del modinit
-
-### Helpers
-
-def _isstring(arg,
-
-              isinstance=isinstance, types=_types):
-    
-    if isinstance(arg, types.StringType):
-        return 1
-    try:
-        if isinstance(arg, types.UnicodeType):
-            return 1
-    except AttributeError:
-        pass
-    return 0
-
-### Compatibility APIs
-
-# Aliases and functions to make 'from mx.DateTime import *' work much
-# like 'from time import *'
-
-def localtime(ticks=None,
-              # Locals:
-              time=_time.time,float=float,localtime=_time.localtime,
-              round=round,int=int,DateTime=DateTime,floor=_math.floor):
-
-    """localtime(ticks=None)
-
-       Construct a DateTime instance using local time from ticks.  If
-       ticks are not given, it defaults to the current time.  The
-       result is similar to time.localtime(). Fractions of a second
-       are rounded to the nearest micro-second.
-
-    """
-    if ticks is None:
-        ticks = time()
-    else:
-        ticks = float(ticks)
-    ticks = round(ticks, 6)
-    fticks = floor(ticks)
-    Y,M,D,h,m,s = localtime(fticks)[:6]
-    s = s + (ticks - fticks)
-    return DateTime(Y,M,D,h,m,s)
-
-def gmtime(ticks=None,
-           # Locals:
-           time=_time.time,float=float,gmtime=_time.gmtime,
-           round=round,int=int,DateTime=DateTime,floor=_math.floor):
-
-    """gmtime(ticks=None)
-
-       Construct a DateTime instance using UTC time from ticks.  If
-       ticks are not given, it defaults to the current time.  The
-       result is similar to time.gmtime(). Fractions of a second are
-       rounded to the nearest micro-second.
-
-    """
-    if ticks is None:
-        ticks = time()
-    else:
-        ticks = float(ticks)
-    ticks = round(ticks, 6)
-    fticks = floor(ticks)
-    Y,M,D,h,m,s = gmtime(ticks)[:6]
-    s = s + (ticks - fticks)
-    return DateTime(Y,M,D,h,m,s)
-
-def mktime((year,month,day,hour,minute,second,dow,doy,dst),
-           # Locals:
-           DateTime=DateTime):
-
-    """mktime((year,month,day,hour,minute,second,dow,doy,dst))
-
-       Same as the DateTime() constructor accept that the interface
-       used is compatible to the similar time.mktime() API.
-
-       Note that the tuple elements dow, doy and dst are not used in
-       any way.
-      
-    """
-    return DateTime(year,month,day,hour,minute,second)
-
-def ctime(datetime):
-
-    """ctime(datetime)
-
-       Returns a string representation of the given DateTime instance
-       using the current locale's default settings.
-
-    """
-    return datetime.strftime('%c')
-
-def today(hour=0,minute=0,second=0.0,
-          # Locals:
-          localtime=_time.localtime,time=_time.time,DateTime=DateTime):
-
-    """today(hour=0,minute=0,second=0.0)
-
-       Returns a DateTime instance for today (in local time) at the
-       given time (defaults to midnight).
-
-    """
-    Y,M,D = localtime(time())[:3]
-    return DateTime(Y,M,D,hour,minute,second)
-
-def TimeDelta(hours=0.0,minutes=0.0,seconds=0.0,
-              # Locals:
-              DateTimeDelta=DateTimeDelta):
-
-    """TimeDelta(hours=0.0,minutes=0.0,seconds=0.0)
-
-       Returns a DateTimeDelta-object reflecting the given time
-       delta. Seconds can be given as float to indicate fractions.
-
-    """
-    return DateTimeDelta(0,hours,minutes,seconds)
-
-def gm2local(datetime):
-
-    """ gm2local(datetime)
-
-        Convert a DateTime instance holding UTC time to a DateTime
-        instance using local time.
-
-    """
-    return localtime(datetime.gmticks())
-
-def local2gm(datetime):
-
-    """ local2gm(datetime)
-
-        Convert a DateTime instance holding local time to a DateTime
-        instance using UTC time.
-
-    """
-    return gmtime(datetime.ticks())
-
-# Alias
-gmt = utc
-
-# Default value for DateTimeFromTJD's tjd_myriad parameter
-current_myriad = localtime().tjd_myriad
-
-def DateTimeFromTJD(tjd,tjd_myriad=current_myriad):
-
-    """ DateTimeFromTJD(tjd[,myriad])
-
-        Return a DateTime instance for the given Truncated Julian Day.
-        myriad defaults to the TJD myriad current at package import
-        time.
-
-        Note that this version of Truncated Julian Day number does
-        real truncation of important information. It's use is
-        discouraged and unsupported.
-
-    """
-    return DateTimeFromAbsDays(tjd + tjd_myriad * 10000.0 - 1721425.0)
-
-def DateTimeFromJDN(jdn):
-
-    """ DateTimeFromJDN(jdn)
-
-        Return a DateTime instance for the given Julian Day Number.
-
-        References:
-        -----------
-        Gregorian 2000-01-01 12:00:00 corresponds to JDN 2451545.0.
-        Gregorian 1858-11-17 00:00:00.00 corresponds to JDN 2400000.5; MJD 0.0.
-        Julian -4712-01-01 12:00:00.00 corresponds to JDN 0.0.
-        Gregorian -4713-11-24 12:00:00.00 corresponds to JDN 0.0.
-
-    """
-    return DateTimeFromAbsDays(jdn - 1721425.5)
-
-def DateTimeFromMJD(mjd):
-
-    """ DateTimeFromMJD(mjd)
-
-        Return a DateTime instance for the given Modified Julian Day
-        (MJD). The MJD is calculated the same way as the JDN except
-        that 1858-11-17 00:00:00.00 is taken as origin of the scale.
-
-    """
-    return DateTimeFromAbsDays(mjd + 678575.0)
-
-def DateTimeFrom(*args, **kws):
-
-    """ DateTimeFrom(*args, **kws)
-
-        Generic DateTime instance constructor. Can handle parsing
-        strings, numbers and keywords.
-
-        XXX Add support for Unicode.
-
-    """
-    if len(args) == 1:
-        # Single argument
-        arg = args[0]
-        argtype = type(arg)
-        if _isstring(arg):
-            import Parser
-            return apply(Parser.DateTimeFromString, args, kws)
-        elif argtype is DateTimeType:
-            return arg
-        elif argtype is DateTimeDeltaType:
-            raise TypeError,'cannot convert DateTimeDelta to DateTime'
-        else:
-            try:
-                value = float(arg)
-            except (TypeError, ValueError):
-                value = int(arg)
-            assert not kws
-            return DateTimeFromTicks(value)
-
-    elif len(args) > 1:
-        # More than one argument
-        if len(args) == 2 and _isstring(args[0]) and _isstring(args[1]):
-            # interpret as date and time string
-            import Parser
-            return apply(Parser.DateTimeFromString,
-                         (args[0] + ' ' + args[1],),
-                         kws)
-
-        # Assume the arguments are the same as for DateTime()
-        return apply(DateTime, args, kws)
-
-    elif len(kws) > 0:
-        # Keyword arguments; add defaults... today at 0:00:00
-        hour = kws.get('hour',0)
-        minute = kws.get('minute',0)
-        second = kws.get('second',0)
-        today = now()
-        day = kws.get('day',today.day)
-        month = kws.get('month',today.month)
-        year = kws.get('year',today.year)
-        return DateTime(year,month,day,hour,minute,second)
-
-    else:
-        raise TypeError,'cannot convert arguments to DateTime'
-
-def DateTimeDeltaFrom(*args, **kws):
-
-    """ DateTimeDeltaFrom(*args, **kws)
-
-        Generic DateTimeDelta instance constructor. Can handle parsing
-        strings, numbers and keywords.
-
-        XXX Add support for Unicode.
-
-    """
-    if len(args) == 1:
-        # Single argument
-        arg = args[0]
-        if _isstring(arg):
-            import Parser
-            return apply(Parser.DateTimeDeltaFromString, args, kws)
-        elif type(arg) is DateTimeDeltaType:
-            return arg
-        elif type(arg) is DateTimeType:
-            raise TypeError,'cannot convert DateTime to DateTimeDelta'
-        else:
-            try:
-                value = float(arg)
-            except TypeError:
-                value = int(arg)
-            assert not kws
-            return DateTimeDeltaFromSeconds(value)
-
-    elif len(args) > 1:
-        # Assume the arguments are the same as for DateTimeDelta()
-        return apply(DateTimeDelta, args, kws)
-
-    elif len(kws) > 0:
-        # Keyword arguments; default: 00:00:00:00.00
-        hours = kws.get('hours',0)
-        minutes = kws.get('minutes',0)
-        seconds = kws.get('seconds',0.0)
-        days = kws.get('days',0)
-        return DateTimeDelta(days,hours,minutes,seconds)
-
-    else:
-        raise TypeError,'cannot convert arguments to DateTimeDelta'
-
-def TimeDeltaFrom(*args, **kws):
-
-    """ TimeDeltaFrom(*args, **kws)
-
-        Generic TimeDelta instance constructor. Can handle parsing
-        strings, numbers and keywords.
-
-        XXX Add support for Unicode.
-
-    """
-    if len(args) > 1:
-        # Assume the arguments are the same as for TimeDelta(): without
-        # days part !
-        return apply(DateTimeDelta, (0,)+args, kws)
-    else:
-        # Otherwise treat the arguments just like for DateTimeDelta
-        # instances.
-        return apply(DateTimeDeltaFrom, args, kws)
-
-def DateFromTicks(ticks,
-                  # Locals:
-                  DateTime=DateTime,localtime=_time.localtime):
-
-    """ DateFromTicks(ticks)
-
-        Constructs a DateTime instance pointing to the local time date
-        at 00:00:00.00 (midnight) indicated by the given ticks value.
-        The time part is ignored.
-
-    """
-    return apply(DateTime, localtime(ticks)[:3])
-
-def TimestampFromTicks(ticks,
-                       # Locals:
-                       DateTime=DateTime,localtime=_time.localtime):
-
-    """ TimestampFromTicks(ticks)
-
-        Constructs a DateTime instance pointing to the local date and
-        time indicated by the given ticks value.
-
-    """
-    return apply(DateTime, localtime(ticks)[:6])
-
-def TimeFromTicks(ticks,
-                  # Locals:
-                  DateTimeDelta=DateTimeDelta,localtime=_time.localtime):
-
-    """ TimeFromTicks(ticks)
-
-        Constructs a DateTimeDelta instance pointing to the local time
-        indicated by the given ticks value. The date part is ignored.
-
-    """
-    return apply(DateTimeDelta, (0,) + localtime(ticks)[3:6])
-
-# Aliases
-utctime = gmtime
-utc2local = gm2local
-local2utc = local2gm
-DateTimeFromTicks = localtime
-Date = DateTime
-Time = TimeDelta
-Timestamp = DateTime
-DateFrom = DateTimeFrom # XXX should only parse the date part !
-TimeFrom = TimeDeltaFrom
-TimestampFrom = DateTimeFrom
-GregorianDateTime = DateTime
-GregorianDate = Date
-JulianDate = JulianDateTime
-
-
-### For backward compatibility (these are depreciated):
-
-def gmticks(datetime):
-
-    """gmticks(datetime)
-
-       [DEPRECIATED: use the .gmticks() method]
-    
-       Returns a ticks value based on the values stored in
-       datetime under the assumption that they are given in UTC,
-       rather than local time.
-
-    """
-    return datetime.gmticks()
-
-# Alias
-utcticks = gmticks
-
-def tz_offset(datetime,
-              # Locals:
-              oneSecond=oneSecond):
-
-    """tz_offset(datetime)
-
-       [DEPRECIATED: use the .gmtoffset() method]
-    
-       Returns a DateTimeDelta instance representing the UTC
-       offset for datetime assuming that the stored values refer
-       to local time. If you subtract this value from datetime,
-       you'll get UTC time.
-
-    """
-    return datetime.gmtoffset()
-
-### Constants (only English; see Locale.py for other languages)
-
-# Weekdays
-Monday =        0
-Tuesday =       1
-Wednesday =     2
-Thursday =      3
-Friday =        4
-Saturday =      5
-Sunday =        6
-# as mapping
-Weekday = {'Saturday': 5, 6: 'Sunday', 'Sunday': 6, 'Thursday': 3,
-           'Wednesday': 2, 'Friday': 4, 'Tuesday': 1, 'Monday': 0,
-           5: 'Saturday', 4: 'Friday', 3: 'Thursday', 2: 'Wednesday',
-           1: 'Tuesday', 0: 'Monday'}
-
-# Months
-January =       1
-February =      2
-March =         3
-April =         4
-May =           5
-June =          6
-July =          7
-August =        8 
-September =     9
-October =       10
-November =      11
-December =      12
-# as mapping
-Month = {2: 'February', 3: 'March', None: 0, 'July': 7, 11: 'November',
-    'December': 12, 'June': 6, 'January': 1, 'September': 9, 'August':
-    8, 'March': 3, 'November': 11, 'April': 4, 12: 'December', 'May':
-    5, 10: 'October', 9: 'September', 8: 'August', 7: 'July', 6:
-    'June', 5: 'May', 4: 'April', 'October': 10, 'February': 2, 1:
-    'January', 0: None}
-
-# Limits (see also the range checks in mxDateTime.c)
-MaxDateTime = DateTime(5867440,12,31) 
-MinDateTime = DateTime(-5851455,1,1)
-MaxDateTimeDelta = DateTimeDeltaFromSeconds(2147483647 * 86400.0)
-MinDateTimeDelta = -MaxDateTimeDelta
-
-###
-
-class RelativeDateTime:
-
-    """RelativeDateTime(years=0,months=0,days=0,
-                  hours=0,minutes=0,seconds=0,
-                  year=0,month=0,day=0,
-                  hour=None,minute=None,second=None,
-                  weekday=None,weeks=None)
-
-       Returns a RelativeDateTime instance for the specified relative
-       time. The constructor handles keywords, so you'll only have to
-       give those parameters which should be changed when you add the
-       relative to an absolute DateTime instance.
-
-       Adding RelativeDateTime instances is supported with the
-       following rules: deltas will be added together, right side
-       absolute values override left side ones.
-
-       Adding RelativeDateTime instances to DateTime instances will
-       return DateTime instances with the appropriate calculations
-       applied, e.g. to get a DateTime instance for the first of next
-       month, you'd call now() + RelativeDateTime(months=+1,day=1).
-
-    """
-    years = 0
-    months = 0
-    days = 0
-    year = None
-    month = 0
-    day = 0
-    hours = 0
-    minutes = 0
-    seconds = 0
-    hour = None
-    minute = None
-    second = None
-    weekday = None
-
-    # cached hash value
-    _hash = None
-
-    # For Zope security:
-    __roles__ = None
-    __allow_access_to_unprotected_subobjects__ = 1
-
-    def __init__(self,
-                 years=0,months=0,days=0,
-                 hours=0,minutes=0,seconds=0,
-                 year=None,month=None,day=None,
-                 hour=None,minute=None,second=None,
-                 weekday=None,weeks=0):
-        
-        self.years = years
-        self.months = months
-        self.days = days + weeks*7
-        self.year = year
-        self.month = month
-        self.day = day
-        self.hours = hours
-        self.minutes = minutes
-        self.seconds = seconds
-        self.hour = hour
-        self.minute = minute
-        self.second = second
-        if weekday is not None:
-            #  Make sure we've got a 2-tuple
-            assert len(weekday) == 2
-            self.weekday = weekday
-
-    def __add__(self,other,
-                # Locals:
-                isinstance=isinstance):
-
-        if isinstance(other,RelativeDateTime):
-            # RelativeDateTime (self) + RelativeDateTime (other)
-
-            r = RelativeDateTime()
-            # date deltas
-            r.years = self.years + other.years
-            r.months = self.months + other.months
-            r.days = self.days + other.days
-            # absolute entries of other override those in self, if given
-            r.year = other.year or self.year
-            r.month = other.month or self.month
-            r.day = other.day or self.day
-            r.weekday = other.weekday or self.weekday
-            # time deltas
-            r.hours = self.hours + other.hours
-            r.minutes = self.minutes + other.minutes
-            r.seconds = self.seconds + other.seconds
-            # absolute entries of other override those in self, if given
-            r.hour = other.hour or self.hour
-            r.minute = other.minute or self.minute
-            r.second = other.second or self.second
-            return r
-
-        else:
-            raise TypeError,"can't add the two types"
-
-    def __radd__(self,other,
-                 # Locals:
-                 isinstance=isinstance,DateTimeType=DateTimeType,
-                 DateTime=DateTime,DateTimeDelta=DateTimeDelta):
-
-        if isinstance(other,DateTimeType):
-            # DateTime (other) + RelativeDateTime (self)
-
-            # date
-            if self.year is None:
-                year = other.year + self.years
-            else:
-                year = self.year + self.years
-            if self.month is None:
-                month = other.month + self.months
-            else:
-                month = self.month + self.months
-            if self.day is None:
-                day = other.day
-            else:
-                day = self.day
-            if day < 0:
-                # fix negative day values
-                month = month + 1
-                day = day + 1
-            day = day + self.days
-            # time
-            if self.hour is None:
-                hour = other.hour + self.hours
-            else:
-                hour = self.hour + self.hours
-            if self.minute is None:
-                minute = other.minute + self.minutes
-            else:
-                minute = self.minute + self.minutes
-            if self.second is None:
-                second = other.second + self.seconds
-            else:
-                second = self.second + self.seconds
-
-            # Refit into proper ranges:
-            if month < 1 or month > 12:
-                month = month - 1
-                yeardelta, monthdelta = divmod(month, 12)
-                year = year + yeardelta
-                month = monthdelta + 1
-
-            # Make sure we have integers
-            year = int(year)
-            month = int(month)
-            day = int(day)
-
-            if self.weekday is None:
-                return DateTime(year, month, 1) + \
-                       DateTimeDelta(day-1,hour,minute,second)
-            
-            # Adjust to the correct weekday
-            day_of_week,index = self.weekday
-            d = DateTime(year, month, 1) + \
-                DateTimeDelta(day-1,hour,minute,second)
-            if index == 0:
-                # 0 index: next weekday if no match
-                return d + (day_of_week - d.day_of_week)
-            elif index > 0:
-                # positive index (1 == first weekday of month)
-                first = d - (d.day - 1)
-                diff = day_of_week - first.day_of_week
-                if diff >= 0:
-                    return first + (diff + (index-1) * 7)
-                else:
-                    return first + (diff + index * 7)
-            else:
-                # negative index (-1 == last weekday of month)
-                last = d + (d.days_in_month - d.day)
-                diff = day_of_week - last.day_of_week
-                if diff <= 0:
-                    return last + (diff + (index+1) * 7)
-                else:
-                    return last + (diff + index * 7)
-            
-        else:
-            raise TypeError,"can't add the two types"
-
-    def __sub__(self,other):
-
-        if isinstance(other,RelativeDateTime):
-            # RelativeDateTime (self) - RelativeDateTime (other)
-
-            r = RelativeDateTime()
-            # date deltas
-            r.years = self.years - other.years
-            r.months = self.months - other.months
-            r.days = self.days - other.days
-            # absolute entries of other override those in self, if given
-            r.year = other.year or self.year
-            r.month = other.month or self.month
-            r.day = other.day or self.day
-            r.weekday = other.weekday or self.weekday
-            # time deltas
-            r.hours = self.hours - other.hours
-            r.minutes = self.minutes - other.minutes
-            r.seconds = self.seconds - other.seconds
-            # absolute entries of other override those in self, if given
-            r.hour = other.hour or self.hour
-            r.minute = other.minute or self.minute
-            r.second = other.second or self.second
-
-            return r
-
-        else:
-            raise TypeError,"can't subtract the two types"
-
-    def __rsub__(self,other,
-                 # Locals:
-                 isinstance=isinstance,DateTimeType=DateTimeType):
-
-        if isinstance(other,DateTimeType):
-            # DateTime (other) - RelativeDateTime (self)
-            return other + self.__neg__()
-
-        else:
-            raise TypeError,"can't subtract the two types"
-
-    def __neg__(self):
-
-        # - RelativeDateTime(self)
-
-        r = RelativeDateTime()
-        # negate date deltas
-        r.years = - self.years
-        r.months = - self.months
-        r.days = - self.days
-        # absolute entries don't change
-        r.year = self.year
-        r.month = self.month
-        r.day = self.day
-        r.weekday = self.weekday
-        # negate time deltas
-        r.hours = - self.hours
-        r.minutes = - self.minutes
-        r.seconds = - self.seconds
-        # absolute entries don't change
-        r.hour = self.hour
-        r.minute = self.minute
-        r.second = self.second
-
-        return r
-
-    def __nonzero__(self):
-
-        # RelativeDateTime instances are considered false in case
-        # they do not define any alterations
-        if (self.year is None and
-            self.years == 0 and
-            self.month is None and
-            self.months == 0 and
-            self.day is None and
-            self.weekday is None and
-            self.days == 0 and
-            self.hour is None and
-            self.hours == 0 and
-            self.minute is None and
-            self.minutes == 0 and
-            self.second is None and
-            self.seconds == 0):
-            return 0
-        else:
-            return 1
-
-    def __mul__(self,other):
-
-        # RelativeDateTime (self) * Number (other)
-        factor = float(other)
-
-        r = RelativeDateTime()
-        # date deltas
-        r.years = factor * self.years
-        r.months = factor * self.months
-        r.days = factor * self.days
-        # time deltas
-        r.hours = factor * self.hours
-        r.minutes = factor * self.minutes
-        r.seconds = factor * self.seconds
-        return r
-
-    __rmul__ = __mul__
-
-    def __div__(self,other):
-
-        # RelativeDateTime (self) / Number (other)
-        return self.__mul__(1/float(other))
-
-    def __eq__(self, other):
-
-        if isinstance(self, RelativeDateTime) and \
-           isinstance(other, RelativeDateTime):
-            # RelativeDateTime (self) == RelativeDateTime (other)
-            if (self.years == other.years and
-                self.months == other.months and
-                self.days == other.days and
-                self.year == other.year and
-                self.day == other.day and
-                self.hours == other.hours and
-                self.minutes == other.minutes and
-                self.seconds == other.seconds and
-                self.hour == other.hour and
-                self.minute == other.minute and
-                self.second == other.second and
-                self.weekday == other.weekday):
-                return 1
-            else:
-                return 0
-        else:
-            raise TypeError,"can't compare the two types"
-
-    def __hash__(self):
-
-        if self._hash is not None:
-            return self._hash
-        x = 1234
-        for value in (self.years, self.months, self.days,
-                      self.year, self.day,
-                      self.hours, self.minutes, self.seconds,
-                      self.hour, self.minute, self.second,
-                      self.weekday):
-            if value is None:
-                x = 135051820 ^ x
-            else:
-                x = hash(value) ^ x
-        self._hash = x
-        return x
-
-    def __str__(self,
-
-                join=_string.join):
-
-        l = []
-        append = l.append
-
-        # Format date part
-        if self.year is not None:
-            append('%04i-' % self.year)
-        elif self.years:
-            append('(%0+5i)-' % self.years)
-        else:
-            append('YYYY-')
-        if self.month is not None:
-            append('%02i-' % self.month)
-        elif self.months:
-            append('(%0+3i)-' % self.months)
-        else:
-            append('MM-')
-        if self.day is not None:
-            append('%02i' % self.day)
-        elif self.days:
-            append('(%0+3i)' % self.days)
-        else:
-            append('DD')
-        if self.weekday:
-            append(' %s:%i' % (Weekday[self.weekday[0]][:3],self.weekday[1]))
-        append(' ')
-        
-        # Normalize relative time values to avoid fractions
-        hours = self.hours
-        minutes = self.minutes
-        seconds = self.seconds
-        hours_fraction = hours - int(hours)
-        minutes = minutes + hours_fraction * 60.0
-        minutes_fraction = minutes - int(minutes)
-        seconds = seconds + minutes_fraction * 6.0
-        seconds_fraction = seconds - int(seconds)
-
-        if 0:
-            # Normalize to standard time ranges
-            if seconds > 60.0:
-                extra_minutes, seconds = divmod(seconds, 60.0)
-                minutes = minutes + extra_minutes
-            elif seconds < -60.0:
-                extra_minutes, seconds = divmod(seconds, -60.0)
-                minutes = minutes - extra_minutes
-            if minutes >= 60.0:
-                extra_hours, minutes = divmod(minutes, 60.0)
-                hours = hours + extra_hours
-            elif minutes <= -60.0:
-                extra_hours, minutes = divmod(minutes, -60.0)
-                hours = hours - extra_hours
-
-        # Format time part
-        if self.hour is not None:
-            append('%02i:' % self.hour)
-        elif hours:
-            append('(%0+3i):' % hours)
-        else:
-            append('HH:')
-        if self.minute is not None:
-            append('%02i:' % self.minute)
-        elif minutes:
-            append('(%0+3i):' % minutes)
-        else:
-            append('MM:')
-        if self.second is not None:
-            append('%02i' % self.second)
-        elif seconds:
-            append('(%0+3i)' % seconds)
-        else:
-            append('SS')
-            
-        return join(l,'')
-
-    def __repr__(self):
-
-        return "<%s instance for '%s' at 0x%x>" % ( 
-            self.__class__.__name__, 
-            self.__str__(), 
-            id(self))
-
-# Alias
-RelativeDate = RelativeDateTime
-
-def RelativeDateTimeFrom(*args, **kws):
-
-    """ RelativeDateTimeFrom(*args, **kws)
-
-        Generic RelativeDateTime instance constructor. Can handle
-        parsing strings and keywords.
-
-    """
-    if len(args) == 1:
-        # Single argument
-        arg = args[0]
-        if _isstring(arg):
-            import Parser
-            return apply(Parser.RelativeDateTimeFromString, args, kws)
-        elif isinstance(arg, RelativeDateTime):
-            return arg
-        else:
-            raise TypeError,\
-                  'cannot convert argument to RelativeDateTime'
-
-    else:
-        return apply(RelativeDateTime,args,kws)
-
-def RelativeDateTimeDiff(date1,date2,
-
-                         floor=_math.floor,int=int,divmod=divmod,
-                         RelativeDateTime=RelativeDateTime):
-
-    """ RelativeDateTimeDiff(date1,date2)
-
-        Returns a RelativeDateTime instance representing the difference
-        between date1 and date2 in relative terms.
-
-        The following should hold: 
-        
-        date2 + RelativeDateDiff(date1,date2) == date1 
-
-        for all dates date1 and date2.
-
-        Note that due to the algorithm used by this function, not the
-        whole range of DateTime instances is supported; there could
-        also be a loss of precision.
-
-        XXX There are still some problems left (thanks to Carel
-        Fellinger for pointing these out):
-
-        29 1 1901 ->  1 3 1901 = 1 month
-        29 1 1901 ->  1 3 1900 = -10 month and -28 days, but
-        29 1 1901 -> 28 2 1900 = -11 month and -1 day
-
-        and even worse:
-
-        >>> print RelativeDateDiff(Date(1900,3,1),Date(1901,2,1))
-        YYYY-(-11)-DD HH:MM:SS
-
-        with:
-
-        >>> print Date(1901,1,29) + RelativeDateTime(months=-11)
-        1900-03-01 00:00:00.00
-        >>> print Date(1901,2,1) + RelativeDateTime(months=-11)
-        1900-03-01 00:00:00.00
-
-    """
-    diff = date1 - date2
-    if diff.days == 0:
-        return RelativeDateTime()
-    date1months = date1.year * 12 + (date1.month - 1)
-    date2months = date2.year * 12 + (date2.month - 1)
-    #print 'months',date1months,date2months
-
-    # Calculate the months difference
-    diffmonths = date1months - date2months
-    #print 'diffmonths',diffmonths
-    if diff.days > 0:
-        years,months = divmod(diffmonths,12)
-    else:
-        years,months = divmod(diffmonths,-12)
-        years = -years
-    date3 = date2 + RelativeDateTime(years=years,months=months)
-    diff3 = date1 - date3
-    days = date1.absdays - date3.absdays
-    #print 'date3',date3,'diff3',diff3,'days',days
-
-    # Correction to ensure that all relative parts have the same sign
-    while days * diff.days < 0:
-        if diff.days > 0:
-            diffmonths = diffmonths - 1
-            years,months = divmod(diffmonths,12)
-        else:
-            diffmonths = diffmonths + 1
-            years,months = divmod(diffmonths,-12)
-            years = -years
-        #print 'diffmonths',diffmonths
-        date3 = date2 + RelativeDateTime(years=years,months=months)
-        diff3 = date1 - date3
-        days = date1.absdays - date3.absdays
-        #print 'date3',date3,'diff3',diff3,'days',days
-
-    # Drop the fraction part of days
-    if days > 0:
-        days = int(floor(days))
-    else:
-        days = int(-floor(-days))
-
-    return RelativeDateTime(years=years,
-                            months=months,
-                            days=days,
-                            hours=diff3.hour,
-                            minutes=diff3.minute,
-                            seconds=diff3.second)
-
-# Aliases
-RelativeDateDiff = RelativeDateTimeDiff
-Age = RelativeDateTimeDiff
-
-###
-
-_current_year = now().year
-_current_century, _current_year_in_century = divmod(_current_year, 100)
-_current_century = _current_century * 100
-
-def add_century(year,
-
-                current_year=_current_year,
-                current_century=_current_century):
-    
-    """ Sliding window approach to the Y2K problem: adds a suitable
-        century to the given year and returns it as integer.
-
-        The window used depends on the current year (at import time).
-        If adding the current century to the given year gives a year
-        within the range current_year-70...current_year+30 [both
-        inclusive], then the current century is added. Otherwise the
-        century (current + 1 or - 1) producing the least difference is
-        chosen.
-
-    """
-    if year > 99:
-        # Take it as-is
-        return year
-    year = year + current_century
-    diff = year - current_year
-    if diff >= -70 and diff <= 30:
-        return year
-    elif diff < -70:
-        return year + 100
-    else:
-        return year - 100
-
-# Reference formulas for JDN taken from the Calendar FAQ:
-
-def gregorian_jdn(year,month,day):
-
-    # XXX These require proper integer division.
-    a = (14-month)/12
-    y = year+4800-a
-    m = month + 12*a - 3
-    return day + (306*m+5)/10 + y*365 + y/4 - y/100 + y/400 - 32045
-
-def julian_jdn(year,month,day):
-
-    # XXX These require proper integer division.
-    a = (14-month)/12
-    y = year+4800-a
-    m = month + 12*a - 3
-    return day + (306*m+5)/10 + y*365 + y/4 - 32083
--- a/embedded/mx/DateTime/ISO.py	Tue Apr 28 13:28:37 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,366 +0,0 @@
-""" This module provides a set of constructors and routines to convert
-    between DateTime[Delta] instances and ISO representations of date
-    and time.
-
-    Note: Timezones are only interpreted by ParseDateTimeGMT(). All
-    other constructors silently ignore the time zone information.
-
-    Copyright (c) 1998-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
-    Copyright (c) 2000-2007, eGenix.com Software GmbH; mailto:info@egenix.com
-    See the documentation for further information on copyrights,
-    or contact the author.
-
-"""
-import DateTime,Timezone
-import re,string
-
-# Grammar: ISO 8601 (not all, but what we need from it)
-_year = '(?P<year>\d?\d\d\d)'
-_month = '(?P<month>\d?\d)'
-_day = '(?P<day>\d?\d)'
-_hour = '(?P<hour>\d?\d)'
-_minute = '(?P<minute>\d?\d)'
-_second = '(?P<second>\d?\d(?:\.\d+)?)'
-_sign = '(?P<sign>[-+])'
-_week = 'W(?P<week>\d?\d)'
-_zone = Timezone.isozone
-
-_weekdate = _year + '-?(?:' + _week + '-?' + _day + '?)?'
-_date = _year + '-?' + '(?:' + _month + '-?' + _day + '?)?'
-_time = _hour + ':?' + _minute + ':?' + _second + '?(?:' + _zone + ')?'
-
-isodatetimeRE = re.compile(_date + '(?:[ T]' + _time + ')?$')
-isodateRE = re.compile(_date + '$')
-isotimeRE = re.compile(_time + '$')
-isodeltaRE = re.compile(_sign + '?' + _time + '$')
-isoweekRE = re.compile(_weekdate + '$')
-isoweektimeRE = re.compile(_weekdate + '(?:[ T]' + _time + ')?$')
-
-def WeekTime(year,isoweek=1,isoday=1,hour=0,minute=0,second=0.0):
-
-    """Week(year,isoweek=1,isoday=1,hour=0,minute=0,second=0.0)
-
-       Returns a DateTime instance pointing to the given ISO week and
-       day.  isoday defaults to 1, which corresponds to Monday in the
-       ISO numbering. The time part is set as given.
-
-    """
-    d = DateTime.DateTime(year,1,1,hour,minute,second)
-    if d.iso_week[0] == year:
-        # 1.1. belongs to year (backup to Monday)
-        return d + (-d.day_of_week + 7 * (isoweek-1) + isoday-1)
-    else:
-        # 1.1. belongs to year-1 (advance to next Monday)
-        return d + (7-d.day_of_week + 7 * (isoweek-1) + isoday-1)
-
-# Alias
-Week = WeekTime
-
-# Aliases for the other constructors (they all happen to already use
-# ISO format)
-Date = DateTime.Date
-Time = DateTime.Time
-TimeDelta = DateTime.TimeDelta
-
-def ParseDateTime(isostring,parse_isodatetime=isodatetimeRE.match,
-
-                  strip=string.strip,atoi=string.atoi,atof=string.atof):
-
-    """ParseDateTime(isostring)
-
-       Returns a DateTime instance reflecting the given ISO date. A
-       time part is optional and must be delimited from the date by a
-       space or 'T'.
-
-       Time zone information is parsed, but not evaluated.
-
-    """
-    s = strip(isostring)
-    date = parse_isodatetime(s)
-    if not date:
-        raise ValueError,'wrong format, use YYYY-MM-DD HH:MM:SS'
-    year,month,day,hour,minute,second,zone = date.groups()
-    year = atoi(year)
-    if month is None:
-        month = 1
-    else:
-        month = atoi(month)
-    if day is None:
-        day = 1
-    else:
-        day = atoi(day)
-    if hour is None:
-        hour = 0
-    else:
-        hour = atoi(hour)
-    if minute is None:
-        minute = 0
-    else:
-        minute = atoi(minute)
-    if second is None:
-        second = 0.0
-    else:
-        second = atof(second)
-    return DateTime.DateTime(year,month,day,hour,minute,second)
-
-def ParseDateTimeGMT(isostring,parse_isodatetime=isodatetimeRE.match,
-
-                     strip=string.strip,atoi=string.atoi,atof=string.atof):
-
-    """ParseDateTimeGMT(isostring)
-
-       Returns a DateTime instance in UTC reflecting the given ISO
-       date. A time part is optional and must be delimited from the
-       date by a space or 'T'. Timezones are honored.
-
-    """
-    s = strip(isostring)
-    date = parse_isodatetime(s)
-    if not date:
-        raise ValueError,'wrong format, use YYYY-MM-DD HH:MM:SS'
-    year,month,day,hour,minute,second,zone = date.groups()
-    year = atoi(year)
-    if month is None:
-        month = 1
-    else:
-        month = atoi(month)
-    if day is None:
-        day = 1
-    else:
-        day = atoi(day)
-    if hour is None:
-        hour = 0
-    else:
-        hour = atoi(hour)
-    if minute is None:
-        minute = 0
-    else:
-        minute = atoi(minute)
-    if second is None:
-        second = 0.0
-    else:
-        second = atof(second)
-    offset = Timezone.utc_offset(zone)
-    return DateTime.DateTime(year,month,day,hour,minute,second) - offset
-
-# Alias
-ParseDateTimeUTC = ParseDateTimeGMT
-
-def ParseDate(isostring,parse_isodate=isodateRE.match,
-
-              strip=string.strip,atoi=string.atoi,atof=string.atof):
-
-    """ParseDate(isostring)
-
-       Returns a DateTime instance reflecting the given ISO date. A
-       time part may not be included.
-
-    """
-    s = strip(isostring)
-    date = parse_isodate(s)
-    if not date:
-        raise ValueError,'wrong format, use YYYY-MM-DD'
-    year,month,day = date.groups()
-    year = atoi(year)
-    if month is None:
-        month = 1
-    else:
-        month = atoi(month)
-    if day is None:
-        day = 1
-    else:
-        day = atoi(day)
-    return DateTime.DateTime(year,month,day)
-
-def ParseWeek(isostring,parse_isoweek=isoweekRE.match,
-
-              strip=string.strip,atoi=string.atoi,atof=string.atof):
-
-    """ParseWeek(isostring)
-
-       Returns a DateTime instance reflecting the given ISO date. A
-       time part may not be included.
-
-    """
-    s = strip(isostring)
-    date = parse_isoweek(s)
-    if not date:
-        raise ValueError,'wrong format, use yyyy-Www-d, e.g. 1998-W01-1'
-    year,week,day = date.groups()
-    year = atoi(year)
-    if week is None:
-        week = 1
-    else:
-        week = atoi(week)
-    if day is None:
-        day = 1
-    else:
-        day = atoi(day)
-    return Week(year,week,day)
-
-def ParseWeekTime(isostring,parse_isoweektime=isoweektimeRE.match,
-
-                  strip=string.strip,atoi=string.atoi,atof=string.atof):
-
-    """ParseWeekTime(isostring)
-
-       Returns a DateTime instance reflecting the given ISO date. A
-       time part is optional and must be delimited from the date by a
-       space or 'T'.
-
-    """
-    s = strip(isostring)
-    date = parse_isoweektime(s)
-    if not date:
-        raise ValueError,'wrong format, use e.g. "1998-W01-1 12:00:30"'
-    year,week,day,hour,minute,second,zone = date.groups()
-    year = atoi(year)
-    if week is None:
-        week = 1
-    else:
-        week = atoi(week)
-    if day is None:
-        day = 1
-    else:
-        day = atoi(day)
-    if hour is None:
-        hour = 0
-    else:
-        hour = atoi(hour)
-    if minute is None:
-        minute = 0
-    else:
-        minute = atoi(minute)
-    if second is None:
-        second = 0.0
-    else:
-        second = atof(second)
-    return WeekTime(year,week,day,hour,minute,second)
-
-def ParseTime(isostring,parse_isotime=isotimeRE.match,
-
-              strip=string.strip,atoi=string.atoi,atof=string.atof):
-
-    """ParseTime(isostring)
-
-       Returns a DateTimeDelta instance reflecting the given ISO time.
-       Hours and minutes must be given, seconds are
-       optional. Fractions of a second may also be used,
-       e.g. 12:23:12.34.
-
-    """
-    s = strip(isostring)
-    time = parse_isotime(s)
-    if not time:
-        raise ValueError,'wrong format, use HH:MM:SS'
-    hour,minute,second,zone = time.groups()
-    hour = atoi(hour)
-    minute = atoi(minute)
-    if second is not None:
-        second = atof(second)
-    else:
-        second = 0.0
-    return DateTime.TimeDelta(hour,minute,second)
-
-def ParseTimeDelta(isostring,parse_isodelta=isodeltaRE.match,
-
-                   strip=string.strip,atoi=string.atoi,atof=string.atof):
-
-    """ParseTimeDelta(isostring)
-
-       Returns a DateTimeDelta instance reflecting the given ISO time
-       as delta. Hours and minutes must be given, seconds are
-       optional. Fractions of a second may also be used,
-       e.g. 12:23:12.34. In addition to the ISO standard a sign may be
-       prepended to the time, e.g. -12:34.
-
-    """
-    s = strip(isostring)
-    time = parse_isodelta(s)
-    if not time:
-        raise ValueError,'wrong format, use [-]HH:MM:SS'
-    sign,hour,minute,second,zone = time.groups()
-    hour = atoi(hour)
-    minute = atoi(minute)
-    if second is not None:
-        second = atof(second)
-    else:
-        second = 0.0
-    if sign and sign == '-':
-        return -DateTime.TimeDelta(hour,minute,second)
-    else:
-        return DateTime.TimeDelta(hour,minute,second)
-
-def ParseAny(isostring):
-
-    """ParseAny(isostring)
-
-       Parses the given string and tries to convert it to a
-       DateTime[Delta] instance.
-
-    """
-    try:
-        return ParseDateTime(isostring)
-    except ValueError:
-        pass
-    try:
-        return ParseWeekTime(isostring)
-    except ValueError:
-        pass
-    try:
-        return ParseTimeDelta(isostring)
-    except ValueError:
-        raise ValueError,'unsupported format: "%s"' % isostring
-
-def str(datetime,tz=None):
-
-    """str(datetime,tz=DateTime.tz_offset(datetime))
-
-       Returns the datetime instance as ISO date string. tz can be
-       given as DateTimeDelta instance providing the time zone
-       difference from datetime's zone to UTC. It defaults to
-       DateTime.tz_offset(datetime) which assumes local time.
-
-    """
-    if tz is None:
-        tz = datetime.gmtoffset()
-    return '%04i-%02i-%02i %02i:%02i:%02i%+03i%02i' % (
-        datetime.year, datetime.month, datetime.day, 
-        datetime.hour, datetime.minute, datetime.second,
-        tz.hour,tz.minute)
-
-def strGMT(datetime):
-
-    """strGMT(datetime)
-
-       Returns the datetime instance as ISO date string assuming it is
-       given in GMT.
-
-    """
-    return '%04i-%02i-%02i %02i:%02i:%02i+0000' % (
-        datetime.year, datetime.month, datetime.day, 
-        datetime.hour, datetime.minute, datetime.second)
-
-def strUTC(datetime):
-
-    """strUTC(datetime)
-
-       Returns the datetime instance as ISO date string assuming it is
-       given in UTC.
-
-    """
-    return '%04i-%02i-%02i %02i:%02i:%02i+0000' % (
-        datetime.year, datetime.month, datetime.day, 
-        datetime.hour, datetime.minute, datetime.second)
-
-# Testing
-if __name__ == '__main__':
-    e = DateTime.Date(1900,1,1)
-    for i in range(100000):
-        d = e + i
-        year,week,day = d.iso_week
-        c = WeekTime(year,week,day)
-        if d != c:
-            print ' Check %s (given; %i) != %s (parsed)' % (d,d.day_of_week,c)
-        elif i % 1000 == 0:
-            print d,'ok'
--- a/embedded/mx/DateTime/Parser.py	Tue Apr 28 13:28:37 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1225 +0,0 @@
-# -*- coding: latin-1 -*-
-
-""" Date/Time string parsing module.
-
-    Note about the Y2K problems:
-
-       The parser can only handle years with at least 2 digits. 2
-       digit year values get expanded by adding the century using
-       DateTime.add_century(), while 3 digit year get converted
-       literally. To have 2 digit years also be interpreted literally,
-       add leading zeros, e.g. year 99 must be written as 099 or 0099.
-
-    Copyright (c) 1998-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
-    Copyright (c) 2000-2007, eGenix.com Software GmbH; mailto:info@egenix.com
-    See the documentation for further information on copyrights,
-    or contact the author. All Rights Reserved.
-
-"""
-import types,re,string
-import DateTime,ISO,ARPA,Timezone
-
-# Enable to produce debugging output
-_debug = 0
-
-# REs for matching date and time parts in a string; These REs
-# parse a superset of ARPA, ISO, American and European style dates.
-# Timezones are supported via the Timezone submodule.
-
-_year = '(?P<year>-?\d+\d(?!:))'
-_fullyear = '(?P<year>-?\d+\d\d(?!:))'
-_year_epoch = '(?:' + _year + '(?P<epoch> *[ABCDE\.]+)?)'
-_fullyear_epoch = '(?:' + _fullyear + '(?P<epoch> *[ABCDE\.]+)?)'
-_relyear = '(?:\((?P<relyear>[-+]?\d+)\))'
-
-_month = '(?P<month>\d?\d(?!:))'
-_fullmonth = '(?P<month>\d\d(?!:))'
-_litmonth = ('(?P<litmonth>'
-             'jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec|'
-             'mär|mae|mrz|mai|okt|dez|'
-             'fev|avr|juin|juil|aou|aoû|déc|'
-             'ene|abr|ago|dic|'
-             'out'
-             ')[a-z,\.;]*')
-litmonthtable = {
-    # English
-    'jan':1, 'feb':2, 'mar':3, 'apr':4, 'may':5, 'jun':6,
-    'jul':7, 'aug':8, 'sep':9, 'oct':10, 'nov':11, 'dec':12,
-    # German
-    'mär':3, 'mae':3, 'mrz':3, 'mai':5, 'okt':10, 'dez':12,
-    # French
-    'fev':2, 'avr':4, 'juin':6, 'juil':7, 'aou':8, 'aoû':8,
-    'déc':12,
-    # Spanish
-    'ene':1, 'abr':4, 'ago':8, 'dic':12,
-    # Portuguese
-    'out':10,
-    }
-_relmonth = '(?:\((?P<relmonth>[-+]?\d+)\))'
-
-_day = '(?P<day>\d?\d(?!:))'
-_usday = '(?P<day>\d?\d(?!:))(?:st|nd|rd|th|[,\.;])?'
-_fullday = '(?P<day>\d\d(?!:))'
-_litday = ('(?P<litday>'
-           'mon|tue|wed|thu|fri|sat|sun|'
-           'die|mit|don|fre|sam|son|'
-           'lun|mar|mer|jeu|ven|sam|dim|'
-           'mie|jue|vie|sab|dom|'
-           'pri|seg|ter|cua|qui'
-           ')[a-z]*')
-litdaytable = {
-    # English
-    'mon':0, 'tue':1, 'wed':2, 'thu':3, 'fri':4, 'sat':5, 'sun':6,
-    # German
-    'die':1, 'mit':2, 'don':3, 'fre':4, 'sam':5, 'son':6,
-    # French
-    'lun':0, 'mar':1, 'mer':2, 'jeu':3, 'ven':4, 'sam':5, 'dim':6,
-    # Spanish
-    'mie':2, 'jue':3, 'vie':4, 'sab':5, 'dom':6,
-    # Portuguese
-    'pri':0, 'seg':1, 'ter':2, 'cua':3, 'qui':4,
-    }
-_relday = '(?:\((?P<relday>[-+]?\d+)\))'
-
-_hour = '(?P<hour>[012]?\d)'
-_minute = '(?P<minute>[0-6]\d)'
-_second = '(?P<second>[0-6]\d(?:[.,]\d+)?)'
-
-_days = '(?P<days>\d*\d(?:[.,]\d+)?)'
-_hours = '(?P<hours>\d*\d(?:[.,]\d+)?)'
-_minutes = '(?P<minutes>\d*\d(?:[.,]\d+)?)'
-_seconds = '(?P<seconds>\d*\d(?:[.,]\d+)?)'
-
-_reldays = '(?:\((?P<reldays>[-+]?\d+(?:[.,]\d+)?)\))'
-_relhours = '(?:\((?P<relhours>[-+]?\d+(?:[.,]\d+)?)\))'
-_relminutes = '(?:\((?P<relminutes>[-+]?\d+(?:[.,]\d+)?)\))'
-_relseconds = '(?:\((?P<relseconds>[-+]?\d+(?:[.,]\d+)?)\))'
-
-_sign = '(?:(?P<sign>[-+]) *)'
-_week = 'W(?P<week>\d?\d)'
-_zone = Timezone.zone
-_ampm = '(?P<ampm>[ap][m.]+)'
-
-_time = (_hour + ':' + _minute + '(?::' + _second + '|[^:]|$) *'
-         + _ampm + '? *' + _zone + '?')
-_isotime = _hour + ':?' + _minute + ':?' + _second + '? *' + _zone + '?'
-
-_weekdate = _year + '-?(?:' + _week + '-?' + _day + '?)?'
-_eurodate = _day + '\.' + _month + '\.' + _year_epoch + '?'
-_usdate = _month + '/' + _day + '(?:/' + _year_epoch + '|[^/]|$)'
-_altusdate = _month + '-' + _day + '-' + _fullyear_epoch
-_isodate = _year + '-' + _month + '-?' + _day + '?(?!:)'
-_altisodate = _year + _fullmonth + _fullday + '(?!:)'
-_usisodate = _fullyear + '/' + _fullmonth + '/' + _fullday
-_litdate = ('(?:'+ _litday + ',? )? *' + 
-            _usday + ' *' + 
-            '[- ] *(?:' + _litmonth + '|'+ _month +') *[- ] *' +
-            _year_epoch + '?')
-_altlitdate = ('(?:'+ _litday + ',? )? *' + 
-               _litmonth + '[ ,.a-z]+' +
-               _usday + 
-               '(?:[ a-z]+' + _year_epoch + ')?')
-_eurlitdate = ('(?:'+ _litday + ',?[ a-z]+)? *' + 
-               '(?:'+ _usday + '[ a-z]+)? *' +
-               _litmonth + 
-               '(?:[ ,.a-z]+' + _year_epoch + ')?')
-
-_relany = '[*%?a-zA-Z]+'
-
-_relisodate = ('(?:(?:' + _relany + '|' + _year + '|' + _relyear + ')-' +
-               '(?:' + _relany + '|' + _month + '|' + _relmonth + ')-' +
-               '(?:' + _relany + '|' + _day + '|' + _relday + '))')
-
-_asctime = ('(?:'+ _litday + ',? )? *' + 
-                _usday + ' *' + 
-                '[- ] *(?:' + _litmonth + '|'+ _month +') *[- ]' +
-                '(?:[0-9: ]+)' + 
-                _year_epoch + '?')
-
-_relisotime = ('(?:(?:' + _relany + '|' + _hour + '|' + _relhours + '):' +
-               '(?:' + _relany + '|' + _minute + '|' + _relminutes + ')' +
-               '(?::(?:' + _relany + '|' + _second + '|' + _relseconds + '))?)')
-
-_isodelta1 = (_sign + '?' +
-              _days + ':' + _hours + ':' + _minutes + ':' + _seconds)
-_isodelta2 = (_sign + '?' + 
-              _hours + ':' + _minutes + ':' + _seconds)
-_isodelta3 = (_sign + '?' + 
-              _hours + ':' + _minutes)
-_litdelta = (_sign + '?' +
-             '(?:' + _days + ' *d[a-z]*[,; ]*)?' + 
-             '(?:' + _hours + ' *h[a-z]*[,; ]*)?' + 
-             '(?:' + _minutes + ' *m[a-z]*[,; ]*)?' +
-             '(?:' + _seconds + ' *s[a-z]*[,; ]*)?')
-_litdelta2 = (_sign + '?' +
-             '(?:' + _days + ' *d[a-z]*[,; ]*)?' + 
-              _hours + ':' + _minutes + '(?::' + _seconds + ')?')
-
-_timeRE = re.compile(_time, re.I)
-_isotimeRE = re.compile(_isotime, re.I)
-_isodateRE = re.compile(_isodate, re.I)
-_altisodateRE = re.compile(_altisodate, re.I)
-_usisodateRE = re.compile(_usisodate, re.I)
-_eurodateRE = re.compile(_eurodate, re.I)
-_usdateRE = re.compile(_usdate, re.I)
-_altusdateRE = re.compile(_altusdate, re.I)
-_litdateRE = re.compile(_litdate, re.I)
-_altlitdateRE = re.compile(_altlitdate, re.I)
-_eurlitdateRE = re.compile(_eurlitdate, re.I)
-_relisodateRE = re.compile(_relisodate, re.I)
-_asctimeRE = re.compile(_asctime, re.I)
-_isodelta1RE = re.compile(_isodelta1)
-_isodelta2RE = re.compile(_isodelta2)
-_isodelta3RE = re.compile(_isodelta3)
-_litdeltaRE = re.compile(_litdelta)
-_litdelta2RE = re.compile(_litdelta2)
-_relisotimeRE = re.compile(_relisotime, re.I)
-
-# Available date parsers
-_date_formats = ('euro',
-                 'usiso', 'us', 'altus',
-                 'iso', 'altiso', 
-                 'lit', 'altlit', 'eurlit',
-                 'unknown')
-
-# Available time parsers
-_time_formats = ('standard',
-                 'iso',
-                 'unknown')
-
-def _parse_date(text, formats=_date_formats, defaultdate=None,
-
-                int=int,float=float,lower=string.lower,
-                add_century=DateTime.add_century,
-                now=DateTime.now,us_formats=('us', 'altus'),
-                iso_formats=('iso', 'altiso', 'usiso')):
-
-    """ Parses the date part given in text and returns a tuple
-        (text,day,month,year,style) with the following
-        meanings:
-
-        * text gives the original text without the date part
-
-        * day,month,year give the parsed date
-
-        * style gives information about which parser was successful:
-          'euro' - the European date parser
-          'us' - the US date parser
-          'altus' - the alternative US date parser (with '-' instead of '/')
-          'iso' - the ISO date parser
-          'altiso' - the alternative ISO date parser (without '-')
-          'usiso' - US style ISO date parser (yyyy/mm/dd)
-          'lit' - the US literal date parser
-          'altlit' - the alternative US literal date parser
-          'eurlit' - the Eurpean literal date parser
-          'unknown' - no date part was found, defaultdate was used
-
-        formats may be set to a tuple of style strings specifying
-        which of the above parsers to use and in which order to try
-        them. Default is to try all of them in the above order.
-
-        defaultdate provides the defaults to use in case no date part
-        is found. Most other parsers default to the current year
-        January 1 if some of these date parts are missing.
-
-        If 'unknown' is not given in formats and the date cannot be
-        parsed, a ValueError is raised.
-
-    """
-    match = None
-    style = ''
-    
-    # Apply parsers in the order given in formats
-    for format in formats:
-
-        if format == 'euro':
-            # European style date
-            match = _eurodateRE.search(text)
-            if match is not None:
-                day,month,year,epoch = match.groups()
-                if year:
-                    if len(year) == 2:
-                        # Y2K problem:
-                        year = add_century(int(year))
-                    else:
-                        year = int(year)
-                else:
-                    if defaultdate is None:
-                        defaultdate = now()
-                    year = defaultdate.year
-                if epoch and 'B' in epoch:
-                    year = -year + 1
-                month = int(month)
-                day = int(day)
-                # Could have mistaken euro format for us style date
-                # which uses month, day order
-                if month > 12 or month == 0:
-                    match = None
-                    continue
-                break
-
-        elif format in iso_formats:
-            # ISO style date
-            if format == 'iso':
-                match = _isodateRE.search(text)
-            elif format == 'altiso':
-                match = _altisodateRE.search(text)
-                # Avoid mistaking ISO time parts ('Thhmmss') for dates
-                if match is not None:
-                    left, right = match.span()
-                    if left > 0 and \
-                       text[left - 1:left] == 'T':
-                        match = None
-                        continue
-            else:
-                match = _usisodateRE.search(text)
-            if match is not None:
-                year,month,day = match.groups()
-                if len(year) == 2:
-                    # Y2K problem:
-                    year = add_century(int(year))
-                else:
-                    year = int(year)
-                # Default to January 1st
-                if not month:
-                    month = 1
-                else:
-                    month = int(month)
-                if not day:
-                    day = 1
-                else:
-                    day = int(day)
-                break
-
-        elif format in us_formats:
-            # US style date
-            if format == 'us':
-                match = _usdateRE.search(text)
-            else:
-                match = _altusdateRE.search(text)
-            if match is not None:
-                month,day,year,epoch = match.groups()
-                if year:
-                    if len(year) == 2:
-                        # Y2K problem:
-                        year = add_century(int(year))
-                    else:
-                        year = int(year)
-                else:
-                    if defaultdate is None:
-                        defaultdate = now()
-                    year = defaultdate.year
-                if epoch and 'B' in epoch:
-                    year = -year + 1
-                # Default to 1 if no day is given
-                if day:
-                    day = int(day)
-                else:
-                    day = 1
-                month = int(month)
-                # Could have mistaken us format for euro style date
-                # which uses day, month order
-                if month > 12 or month == 0:
-                    match = None
-                    continue
-                break
-
-        elif format == 'lit':
-            # US style literal date
-            match = _litdateRE.search(text)
-            if match is not None:
-                litday,day,litmonth,month,year,epoch = match.groups()
-                break
-
-        elif format == 'altlit':
-            # Alternative US style literal date
-            match = _altlitdateRE.search(text)
-            if match is not None: 
-                litday,litmonth,day,year,epoch = match.groups()
-                month = '<missing>'
-                break
-
-        elif format == 'eurlit':
-            # European style literal date
-            match = _eurlitdateRE.search(text)
-            if match is not None: 
-                litday,day,litmonth,year,epoch = match.groups()
-                month = '<missing>'
-                break
-
-        elif format == 'unknown':
-            # No date part: use defaultdate
-            if defaultdate is None:
-                defaultdate = now()
-            year = defaultdate.year
-            month = defaultdate.month
-            day = defaultdate.day
-            style = format
-            break
-
-    # Check success
-    if match is not None:
-        # Remove date from text
-        left, right = match.span()
-        if 0 and _debug:
-            print 'parsed date:',repr(text[left:right]),\
-                  'giving:',year,month,day
-        text = text[:left] + text[right:]
-        style = format
-        
-    elif not style:
-        # Not recognized: raise an error
-        raise ValueError, 'unknown date format: "%s"' % text
-
-    # Literal date post-processing
-    if style in ('lit', 'altlit', 'eurlit'):
-        if 0 and _debug: print match.groups()
-        # Default to current year, January 1st
-        if not year:
-            if defaultdate is None:
-                defaultdate = now()
-            year = defaultdate.year
-        else:
-            if len(year) == 2:
-                # Y2K problem:
-                year = add_century(int(year))
-            else:
-                year = int(year)
-        if epoch and 'B' in epoch:
-            year = -year + 1
-        if litmonth:
-            litmonth = lower(litmonth)
-            try:
-                month = litmonthtable[litmonth]
-            except KeyError:
-                raise ValueError,\
-                      'wrong month name: "%s"' % litmonth
-        elif month:
-            month = int(month)
-        else:
-            month = 1
-        if day:
-            day = int(day)
-        else:
-            day = 1
-
-    #print '_parse_date:',text,day,month,year,style
-    return text,day,month,year,style
-
-def _parse_time(text, formats=_time_formats,
-
-                int=int,float=float,replace=string.replace):
-
-    """ Parses a time part given in text and returns a tuple
-        (text,hour,minute,second,offset,style) with the following
-        meanings:
-
-        * text gives the original text without the time part
-        * hour,minute,second give the parsed time
-        * offset gives the time zone UTC offset
-        * style gives information about which parser was successful:
-          'standard' - the standard parser
-          'iso' - the ISO time format parser
-          'unknown' - no time part was found
-
-        formats may be set to a tuple specifying the parsers to use:
-          'standard' - standard time format with ':' delimiter
-          'iso' - ISO time format (superset of 'standard')
-          'unknown' - default to 0:00:00, 0 zone offset
-
-        If 'unknown' is not given in formats and the time cannot be
-        parsed, a ValueError is raised.
-
-    """
-    match = None
-    style = ''
-
-    # Apply parsers in the order given in formats
-    for format in formats:
-
-        # Standard format
-        if format == 'standard':
-            match = _timeRE.search(text)
-            if match is not None:
-                hour,minute,second,ampm,zone = match.groups()
-                style = 'standard'
-                break
-
-        # ISO format
-        if format == 'iso':
-            match =  _isotimeRE.search(text)
-            if match is not None:
-                hour,minute,second,zone = match.groups()
-                ampm = None
-                style = 'iso'
-                break
-
-        # Default handling
-        elif format == 'unknown':
-            hour,minute,second,offset = 0,0,0.0,0
-            style = 'unknown'
-            break
-
-    if not style:
-        # If no default handling should be applied, raise an error
-        raise ValueError, 'unknown time format: "%s"' % text
-
-    # Post-processing
-    if match is not None:
-        if zone:
-            # Convert to UTC offset
-            offset = Timezone.utc_offset(zone)
-        else:
-            offset = 0
-        hour = int(hour)
-        if ampm:
-            if ampm[0] in ('p', 'P'):
-                # 12pm = midday
-                if hour < 12:
-                    hour = hour + 12
-            else:
-                # 12am = midnight 
-                if hour >= 12:
-                    hour = hour - 12
-        if minute:
-            minute = int(minute)
-        else:
-            minute = 0
-        if not second:
-            second = 0.0
-        else:
-            if ',' in second:
-                second = replace(second, ',', '.')
-            second = float(second)
-
-        # Remove time from text
-        left,right = match.span()
-        if 0 and _debug: 
-            print 'parsed time:',repr(text[left:right]),\
-                  'giving:',hour,minute,second,offset
-        text = text[:left] + text[right:]
-
-    #print '_parse_time:',text,hour,minute,second,offset,style
-    return text,hour,minute,second,offset,style
-
-###
-
-def DateTimeFromString(text, formats=_date_formats, defaultdate=None,
-                       time_formats=_time_formats,
-
-                       DateTime=DateTime):
-
-    """ DateTimeFromString(text, [formats, defaultdate])
-    
-        Returns a DateTime instance reflecting the date and time given
-        in text. In case a timezone is given, the returned instance
-        will point to the corresponding UTC time value. Otherwise, the
-        value is set as given in the string.
-
-        formats may be set to a tuple of strings specifying which of
-        the following parsers to use and in which order to try
-        them. Default is to try all of them in the order given below:
-
-          'euro' - the European date parser
-          'us' - the US date parser
-          'altus' - the alternative US date parser (with '-' instead of '/')
-          'iso' - the ISO date parser
-          'altiso' - the alternative ISO date parser (without '-')
-          'usiso' - US style ISO date parser (yyyy/mm/dd)
-          'lit' - the US literal date parser
-          'altlit' - the alternative US literal date parser
-          'eurlit' - the Eurpean literal date parser
-          'unknown' - if no date part is found, use defaultdate
-
-        defaultdate provides the defaults to use in case no date part
-        is found. Most of the parsers default to the current year
-        January 1 if some of these date parts are missing.
-
-        If 'unknown' is not given in formats and the date cannot
-        be parsed, a ValueError is raised.
-
-        time_formats may be set to a tuple of strings specifying which
-        of the following parsers to use and in which order to try
-        them. Default is to try all of them in the order given below:
-
-          'standard' - standard time format HH:MM:SS (with ':' delimiter)
-          'iso' - ISO time format (superset of 'standard')
-          'unknown' - default to 00:00:00 in case the time format
-                      cannot be parsed
-
-        Defaults to 00:00:00.00 for time parts that are not included
-        in the textual representation.
-
-        If 'unknown' is not given in time_formats and the time cannot
-        be parsed, a ValueError is raised.
-
-    """
-    origtext = text
-    formats = tuple(formats)
-
-    if formats is _date_formats or \
-       'iso' in formats or \
-       'altiso' in formats:
-
-        # First try standard order (parse time, then date)
-        if formats[0] not in ('iso', 'altiso'):
-            text,hour,minute,second,offset,timestyle = _parse_time(
-                origtext,
-                time_formats)
-            text,day,month,year,datestyle = _parse_date(
-                text,
-                formats + ('unknown',),
-                defaultdate)
-            if 0 and _debug:
-                print 'tried time/date on %s, date=%s, time=%s' % (origtext,
-                                                                   datestyle,
-                                                                   timestyle)
-        else:
-            timestyle = 'iso'
-            
-        # If this fails, try the ISO order (date, then time)
-        if timestyle in ('iso', 'unknown'):
-            text,day,month,year,datestyle = _parse_date(
-                origtext,
-                formats,
-                defaultdate)
-            text,hour,minute,second,offset,timestyle = _parse_time(
-                text,
-                time_formats)
-            if 0 and _debug:
-                print 'tried ISO on %s, date=%s, time=%s' % (origtext,
-                                                             datestyle,
-                                                             timestyle)
-    else:
-        # Standard order: time part, then date part
-        text,hour,minute,second,offset,timestyle = _parse_time(
-            origtext,
-            time_formats)
-        text,day,month,year,datestyle = _parse_date(
-            text,
-            formats,
-            defaultdate)
-
-    if (datestyle == 'unknown' and 'unknown' not in formats) or \
-       (timestyle == 'unknown' and 'unknown' not in time_formats):
-        raise ValueError,\
-              'Failed to parse "%s": found "%s" date, "%s" time' % \
-              (origtext, datestyle, timestyle)
-    
-    try:
-        return DateTime.DateTime(year,month,day,hour,minute,second) - offset
-    except DateTime.RangeError, why:
-        raise DateTime.RangeError,\
-              'Failed to parse "%s": %s' % (origtext, why)
-
-def DateFromString(text, formats=_date_formats, defaultdate=None,
-
-                   DateTime=DateTime):
-
-    """ DateFromString(text, [formats, defaultdate])
-    
-        Returns a DateTime instance reflecting the date given in
-        text. A possibly included time part is ignored.
-
-        formats and defaultdate work just like for
-        DateTimeFromString().
-
-    """
-    _text,day,month,year,datestyle = _parse_date(text, formats, defaultdate)
-
-    if datestyle == 'unknown' and \
-       'unknown' not in formats:
-        raise ValueError,\
-              'Failed to parse "%s": found "%s" date' % \
-              (origtext, datestyle)
-
-    try:
-        return DateTime.DateTime(year,month,day)
-    except DateTime.RangeError, why:
-        raise DateTime.RangeError,\
-              'Failed to parse "%s": %s' % (text, why)
-
-def validateDateTimeString(text, formats=_date_formats):
-
-    """ validateDateTimeString(text, [formats, defaultdate])
-
-        Validates the given text and returns 1/0 depending on whether
-        text includes parseable date and time values or not.
-
-        formats works just like for DateTimeFromString() and defines
-        the order of date/time parsers to apply. It defaults to the
-        same list of parsers as for DateTimeFromString().
-
-        XXX Undocumented !
-    
-    """
-    formats = list(formats)
-    if 'unknown' in formats:
-        formats.remove('unknown')
-    try:
-        DateTimeFromString(text, formats)
-    except (DateTime.RangeError, ValueError), why:
-        return 0
-    return 1
-
-def validateDateString(text, formats=_date_formats):
-
-    """ validateDateString(text, [formats, defaultdate])
-
-        Validates the given text and returns 1/0 depending on whether
-        text includes a parseable date value or not.
-
-        formats works just like for DateTimeFromString() and defines
-        the order of date/time parsers to apply. It defaults to the
-        same list of parsers as for DateTimeFromString().
-    
-        XXX Undocumented !
-    
-    """
-    formats = list(formats)
-    if 'unknown' in formats:
-        formats.remove('unknown')
-    try:
-        DateFromString(text, formats)
-    except (DateTime.RangeError, ValueError), why:
-        return 0
-    return 1
-
-def TimeFromString(text, formats=_time_formats,
-
-                   DateTime=DateTime):
-
-    """ TimeFromString(text, [formats])
-    
-        Returns a DateTimeDelta instance reflecting the time given in
-        text. A possibly included date part is ignored.
-
-        formats may be set to a tuple of strings specifying which of
-        the following parsers to use and in which order to try
-        them. Default is to try all of them in the order given below:
-
-          'standard' - standard time format with ':' delimiter
-          'iso' - ISO time format (superset of 'standard')
-          'unknown' - default to 00:00:00 in case the time format
-                      cannot be parsed
-
-        Defaults to 00:00:00.00 for parts that are not included in the
-        textual representation.
-        
-    """
-    _text,hour,minute,second,offset,timestyle = _parse_time(
-        text,
-        formats)
-
-    if timestyle == 'unknown' and \
-       'unknown' not in formats:
-        raise ValueError,\
-              'Failed to parse "%s": found "%s" time' % \
-              (text, timestyle)
-
-    try:
-        dtd = DateTime.DateTimeDelta(0.0, hour, minute, second)
-    except DateTime.RangeError, why:
-        raise DateTime.RangeError,\
-              'Failed to parse "%s": %s' % (text, why)
-    else:
-        # XXX What to do with offset ?
-        return dtd
-
-#
-# XXX Still missing: validateTimeString(), validateDateTimeDeltaString()
-#                    and validateTimeDeltaString()
-#
-
-def DateTimeDeltaFromString(text,
-
-                            float=float,DateTime=DateTime):
-
-    """ DateTimeDeltaFromString(text)
-    
-        Returns a DateTimeDelta instance reflecting the delta given in
-        text. Defaults to 0:00:00:00.00 for parts that are not
-        included in the textual representation or cannot be parsed.
-
-    """
-    match = _isodelta1RE.search(text)
-    if match is not None:
-        sign, days, hours, minutes, seconds = match.groups()
-    else:
-        match = _litdelta2RE.search(text)
-        if match is not None:
-            sign, days, hours, minutes, seconds = match.groups()
-        else:
-            match = _isodelta2RE.search(text)
-            if match is not None:
-                sign, hours, minutes, seconds = match.groups()
-                days = None
-            else:
-                match = _isodelta3RE.search(text)
-                if match is not None:
-                    sign, hours, minutes = match.groups()
-                    days = None
-                    seconds = None
-                else:
-                    match = _litdeltaRE.search(text)
-                    if match is not None:
-                        sign, days, hours, minutes, seconds = match.groups()
-
-                    else:
-                        # Not matched:
-                        return DateTime.DateTimeDelta(0.0)
-
-    # Conversions
-    if days:
-        days = float(days)
-    else:
-        days = 0.0
-    if hours:
-        hours = float(hours)
-    else:
-        hours = 0.0
-    if minutes:
-        minutes = float(minutes)
-    else:
-        minutes = 0.0
-    if seconds:
-        seconds = float(seconds)
-    else:
-        seconds = 0.0
-    if sign != '-':
-        sign = 1
-    else:
-        sign = -1
-
-    try:
-        dtd = DateTime.DateTimeDelta(days,hours,minutes,seconds)
-    except DateTime.RangeError, why:
-        raise DateTime.RangeError,\
-              'Failed to parse "%s": %s' % (text, why)
-    else:
-        if sign < 0:
-            return -dtd
-        else:
-            return dtd
-
-# Aliases
-TimeDeltaFromString = DateTimeDeltaFromString
-
-###
-
-def _parse_reldate(text,
-
-                   int=int,float=float):
-
-    match = _relisodateRE.search(text)
-    if match is not None:
-        groups = match.groups()
-        if 0 and _debug: print groups
-        year,years,month,months,day,days = groups
-        if year:
-            year = int(year)
-        if years:
-            years = float(years)
-        else:
-            years = 0
-        if month:
-            month = int(month)
-        if months:
-            months = float(months)
-        else:
-            months = 0
-        if day:
-            day = int(day)
-        if days:
-            days = float(days)
-        else:
-            days = 0
-        return year,years,month,months,day,days
-    else:
-        return None,0,None,0,None,0
-
-def _parse_reltime(text,
-
-                   int=int,float=float):
-
-    match = _relisotimeRE.search(text)
-    if match is not None:
-        groups = match.groups()
-        if 0 and _debug: print groups
-        hour,hours,minute,minutes,second,seconds = groups
-        if hour:
-            hour = int(hour)
-        if hours:
-            hours = float(hours)
-        else:
-            hours = 0
-        if minute:
-            minute = int(minute)
-        if minutes:
-            minutes = float(minutes)
-        else:
-            minutes = 0
-        if second:
-            second = int(second)
-        if seconds:
-            seconds = float(seconds)
-        else:
-            seconds = 0
-        return hour,hours,minute,minutes,second,seconds
-    else:
-        return None,0,None,0,None,0
-
-def RelativeDateTimeFromString(text,
-
-                               RelativeDateTime=DateTime.RelativeDateTime):
-
-    """ RelativeDateTimeFromString(text)
-    
-        Returns a RelativeDateTime instance reflecting the relative
-        date and time given in text.
-
-        Defaults to wildcards for parts or values which are not
-        included in the textual representation or cannot be parsed.
-
-        The format used in text must adhere to the following syntax:
-
-                        [YYYY-MM-DD] [HH:MM[:SS]]
-
-        with the usual meanings. Values which should not be altered
-        may be replaced with '*', '%', '?' or any combination of
-        letters, e.g. 'YYYY'. Relative settings must be enclosed in
-        parenthesis if given and should include a sign, e.g. '(+0001)'
-        for the year part. All other settings are interpreted as
-        absolute values.
-
-        Date and time parts are both optional as a whole. Seconds in
-        the time part are optional too. Everything else (including the
-        hyphens and colons) is mandatory.
-
-    """
-    year,years,month,months,day,days = _parse_reldate(text)
-    hour,hours,minute,minutes,second,seconds = _parse_reltime(text)
-    return RelativeDateTime(year=year,years=years,
-                            month=month,months=months,
-                            day=day,days=days,
-                            hour=hour,hours=hours,
-                            minute=minute,minutes=minutes,
-                            second=second,seconds=seconds)
-
-def RelativeDateFromString(text,
-
-                           RelativeDateTime=DateTime.RelativeDateTime):
-
-    """ RelativeDateFromString(text)
-    
-        Same as RelativeDateTimeFromString(text) except that only the
-        date part of text is taken into account.
-
-    """
-    year,years,month,months,day,days = _parse_reldate(text)
-    return RelativeDateTime(year=year,years=years,
-                            month=month,months=months,
-                            day=day,days=days)
-
-def RelativeTimeFromString(text,
-
-                           RelativeDateTime=DateTime.RelativeDateTime):
-
-    """ RelativeTimeFromString(text)
-    
-        Same as RelativeDateTimeFromString(text) except that only the
-        time part of text is taken into account.
-
-    """
-    hour,hours,minute,minutes,second,seconds = _parse_reltime(text)
-    return RelativeDateTime(hour=hour,hours=hours,
-                            minute=minute,minutes=minutes,
-                            second=second,seconds=seconds)
-
-### Tests
-
-def _test():
-
-    import sys
-
-    t = DateTime.now()
-
-    print 'Testing DateTime Parser...'
-
-    l = [
-
-        # Literal formats
-        ('Sun Nov  6 08:49:37 1994', '1994-11-06 08:49:37.00'),
-        ('sun nov  6 08:49:37 1994', '1994-11-06 08:49:37.00'),
-        ('sUN NOV  6 08:49:37 1994', '1994-11-06 08:49:37.00'),
-        ('Sunday, 06-Nov-94 08:49:37 GMT', '1994-11-06 08:49:37.00'),
-        ('Sun, 06 Nov 1994 08:49:37 GMT', '1994-11-06 08:49:37.00'),
-        ('06-Nov-94 08:49:37', '1994-11-06 08:49:37.00'),
-        ('06-Nov-94', '1994-11-06 00:00:00.00'),
-        ('06-NOV-94', '1994-11-06 00:00:00.00'),
-        ('November 19 08:49:37', '%s-11-19 08:49:37.00' % t.year),
-        ('Nov. 9', '%s-11-09 00:00:00.00' % t.year),
-        ('Sonntag, der 6. November 1994, 08:49:37 GMT', '1994-11-06 08:49:37.00'),
-        ('6. November 2001, 08:49:37', '2001-11-06 08:49:37.00'),
-        ('sep 6', '%s-09-06 00:00:00.00' % t.year),
-        ('sep 6 2000', '2000-09-06 00:00:00.00'),
-        ('September 29', '%s-09-29 00:00:00.00' % t.year),
-        ('Sep. 29', '%s-09-29 00:00:00.00' % t.year),
-        ('6 sep', '%s-09-06 00:00:00.00' % t.year),
-        ('29 September', '%s-09-29 00:00:00.00' % t.year),
-        ('29 Sep.', '%s-09-29 00:00:00.00' % t.year),
-        ('sep 6 2001', '2001-09-06 00:00:00.00'),
-        ('Sep 6, 2001', '2001-09-06 00:00:00.00'),
-        ('September 6, 2001', '2001-09-06 00:00:00.00'),
-        ('sep 6 01', '2001-09-06 00:00:00.00'),
-        ('Sep 6, 01', '2001-09-06 00:00:00.00'),
-        ('September 6, 01', '2001-09-06 00:00:00.00'),
-        ('30 Apr 2006 20:19:00', '2006-04-30 20:19:00.00'),
-        
-        # ISO formats
-        ('1994-11-06 08:49:37', '1994-11-06 08:49:37.00'),
-        ('010203', '2001-02-03 00:00:00.00'),
-        ('2001-02-03 00:00:00.00', '2001-02-03 00:00:00.00'),
-        ('2001-02 00:00:00.00', '2001-02-01 00:00:00.00'),
-        ('2001-02-03', '2001-02-03 00:00:00.00'),
-        ('2001-02', '2001-02-01 00:00:00.00'),
-        ('20000824/2300', '2000-08-24 23:00:00.00'),
-        ('20000824/0102', '2000-08-24 01:02:00.00'),
-        ('20000824', '2000-08-24 00:00:00.00'),
-        ('20000824/020301', '2000-08-24 02:03:01.00'),
-        ('20000824 020301', '2000-08-24 02:03:01.00'),
-        ('-20000824 020301', '-2000-08-24 02:03:01.00'),
-        ('20000824T020301', '2000-08-24 02:03:01.00'),
-        ('20000824 020301', '2000-08-24 02:03:01.00'),
-        ('2000-08-24 02:03:01.00', '2000-08-24 02:03:01.00'),
-        ('T020311', '%s 02:03:11.00' % t.date),
-        ('2003-12-9', '2003-12-09 00:00:00.00'),
-        ('03-12-9', '2003-12-09 00:00:00.00'),
-        ('003-12-9', '0003-12-09 00:00:00.00'),
-        ('0003-12-9', '0003-12-09 00:00:00.00'),
-        ('2003-1-9', '2003-01-09 00:00:00.00'),
-        ('03-1-9', '2003-01-09 00:00:00.00'),
-        ('003-1-9', '0003-01-09 00:00:00.00'),
-        ('0003-1-9', '0003-01-09 00:00:00.00'),
-
-        # US formats
-        ('06/11/94 08:49:37', '1994-06-11 08:49:37.00'),
-        ('11/06/94 08:49:37', '1994-11-06 08:49:37.00'),
-        ('9/23/2001', '2001-09-23 00:00:00.00'),
-        ('9-23-2001', '2001-09-23 00:00:00.00'),
-        ('9/6', '%s-09-06 00:00:00.00' % t.year),
-        ('09/6', '%s-09-06 00:00:00.00' % t.year),
-        ('9/06', '%s-09-06 00:00:00.00' % t.year),
-        ('09/06', '%s-09-06 00:00:00.00' % t.year),
-        ('9/6/2001', '2001-09-06 00:00:00.00'),
-        ('09/6/2001', '2001-09-06 00:00:00.00'),
-        ('9/06/2001', '2001-09-06 00:00:00.00'),
-        ('09/06/2001', '2001-09-06 00:00:00.00'),
-        ('9-6-2001', '2001-09-06 00:00:00.00'),
-        ('09-6-2001', '2001-09-06 00:00:00.00'),
-        ('9-06-2001', '2001-09-06 00:00:00.00'),
-        ('09-06-2001', '2001-09-06 00:00:00.00'),
-        ('2002/05/28 13:10:56.1147 GMT+2', '2002-05-28 13:10:56.11'),
-        ('1970/01/01', '1970-01-01 00:00:00.00'),
-        ('20021025 12:00 PM', '2002-10-25 12:00:00.00'),
-        ('20021025 12:30 PM', '2002-10-25 12:30:00.00'),
-        ('20021025 12:00 AM', '2002-10-25 00:00:00.00'),
-        ('20021025 12:30 AM', '2002-10-25 00:30:00.00'),
-        ('20021025 1:00 PM', '2002-10-25 13:00:00.00'),
-        ('20021025 2:00 AM', '2002-10-25 02:00:00.00'),
-        ('Thursday, February 06, 2003 12:40 PM', '2003-02-06 12:40:00.00'),
-        ('Mon, 18 Sep 2006 23:03:00', '2006-09-18 23:03:00.00'),
-
-        # European formats
-        ('6.11.2001, 08:49:37', '2001-11-06 08:49:37.00'),
-        ('06.11.2001, 08:49:37', '2001-11-06 08:49:37.00'),
-        ('06.11. 08:49:37', '%s-11-06 08:49:37.00' % t.year),
-        #('21/12/2002', '2002-12-21 00:00:00.00'),
-        #('21/08/2002', '2002-08-21 00:00:00.00'),
-        #('21-08-2002', '2002-08-21 00:00:00.00'),
-        #('13/01/03', '2003-01-13 00:00:00.00'),
-        #('13/1/03', '2003-01-13 00:00:00.00'),
-        #('13/1/3', '2003-01-13 00:00:00.00'),
-        #('13/01/3', '2003-01-13 00:00:00.00'),
-
-        # Time only formats
-        ('01:03', '%s 01:03:00.00' % t.date),
-        ('01:03:11', '%s 01:03:11.00' % t.date),
-        ('01:03:11.50', '%s 01:03:11.50' % t.date),
-        ('01:03:11.50 AM', '%s 01:03:11.50' % t.date),
-        ('01:03:11.50 PM', '%s 13:03:11.50' % t.date),
-        ('01:03:11.50 a.m.', '%s 01:03:11.50' % t.date),
-        ('01:03:11.50 p.m.', '%s 13:03:11.50' % t.date),
-
-        # Invalid formats
-        ('6..2001, 08:49:37', '%s 08:49:37.00' % t.date),
-        ('9//2001', 'ignore'),
-        ('06--94 08:49:37', 'ignore'),
-        ('20000824020301', 'ignore'),
-        ('20-03 00:00:00.00', 'ignore'),
-        ('9/2001', 'ignore'),
-        ('9-6', 'ignore'),
-        ('09-6', 'ignore'),
-        ('9-06', 'ignore'),
-        ('09-06', 'ignore'),
-        ('20000824/23', 'ignore'),
-        ('November 1994 08:49:37', 'ignore'),
-        ('Nov. 94', 'ignore'),
-        ('Mon, 18 Sep 2006 23:03:00 +1234567890', 'ignore'),
-
-        ]
-
-    # Add Unicode versions
-    try:
-        unicode
-    except NameError:
-        pass
-    else:
-        k = []
-        for text, result in l:
-            k.append((unicode(text), result))
-        l.extend(k)
-
-    for text, reference in l:
-        try:
-            value = DateTimeFromString(text)
-        except:
-            if reference is None:
-                continue
-            else:
-                value = str(sys.exc_info()[1])
-        valid_datetime = validateDateTimeString(text)
-        valid_date = validateDateString(text)
-        if str(value) != reference and \
-           not reference == 'ignore':
-            print 'Failed to parse "%s"' % text
-            print '  expected: %s' % (reference or '<exception>')
-            print '  parsed:   %s' % value
-        elif _debug:
-            print 'Parsed "%s" successfully' % text
-        if _debug:
-            if not valid_datetime:
-                print '  "%s" failed date/time validation' % text
-            if not valid_date:
-                print '  "%s" failed date validation' % text
-
-    et = DateTime.now()
-    print 'done. (after %f seconds)' % ((et-t).seconds)
-
-    ###
-
-    print 'Testing DateTimeDelta Parser...'
-
-    t = DateTime.now()
-    l = [
-
-        # Literal formats
-        ('Sun Nov  6 08:49:37 1994', '08:49:37.00'),
-        ('1 day, 8 hours, 49 minutes, 37 seconds', '1:08:49:37.00'),
-        ('10 days, 8 hours, 49 minutes, 37 seconds', '10:08:49:37.00'),
-        ('8 hours, 49 minutes, 37 seconds', '08:49:37.00'),
-        ('49 minutes, 37 seconds', '00:49:37.00'),
-        ('37 seconds', '00:00:37.00'),
-        ('37.5 seconds', '00:00:37.50'),
-        ('8 hours later', '08:00:00.00'),
-        ('2 days', '2:00:00:00.00'),
-        ('2 days 23h', '2:23:00:00.00'),
-        ('2 days 23:57', '2:23:57:00.00'),
-        ('2 days 23:57:13', '2:23:57:13.00'),
-        ('', '00:00:00.00'),
-        
-        # ISO formats
-        ('1994-11-06 08:49:37', '08:49:37.00'),
-        ('10:08:49:37', '10:08:49:37.00'),
-        ('08:49:37', '08:49:37.00'),
-        ('08:49', '08:49:00.00'),
-        ('-10:08:49:37', '-10:08:49:37.00'),
-        ('-08:49:37', '-08:49:37.00'),
-        ('-08:49', '-08:49:00.00'),
-        ('- 10:08:49:37', '-10:08:49:37.00'),
-        ('- 08:49:37', '-08:49:37.00'),
-        ('- 08:49', '-08:49:00.00'),
-        ('10:08:49:37.5', '10:08:49:37.50'),
-        ('08:49:37.5', '08:49:37.50'),
-        ('10:8:49:37', '10:08:49:37.00'),
-        ('8:9:37', '08:09:37.00'),
-        ('8:9', '08:09:00.00'),
-        ('8', '00:00:00.00'),
-
-        # Invalid formats
-        #('', None),
-        #('8', None),
-
-        ]
-
-    for text, reference in l:
-        try:
-            value = DateTimeDeltaFromString(text)
-        except:
-            if reference is None:
-                continue
-            else:
-                value = str(sys.exc_info()[1])
-        if str(value) != reference and \
-           not reference == 'ignore':
-            print 'Failed to parse "%s"' % text
-            print '  expected: %s' % (reference or '<exception>')
-            print '  parsed:   %s' % value
-        elif _debug:
-            print 'Parsed "%s" successfully' % text
-
-    et = DateTime.now()
-    print 'done. (after %f seconds)' % ((et-t).seconds)
-
-    ###
-
-    print 'Testing Time Parser...'
-
-    t = DateTime.now()
-    l = [
-
-        # Standard formats
-        ('08:49:37 AM', '08:49:37.00'),
-        ('08:49:37 PM', '20:49:37.00'),
-        ('12:00:00 AM', '00:00:00.00'),
-        ('12:00:00 PM', '12:00:00.00'),
-        ('8:09:37', '08:09:37.00'),
-        ('8:09', '08:09:00.00'),
-        
-        # ISO formats
-        ('08:49:37', '08:49:37.00'),
-        ('08:49', '08:49:00.00'),
-        ('08:49:37.5', '08:49:37.50'),
-        ('08:49:37,5', '08:49:37.50'),
-        ('08:09', '08:09:00.00'),
-
-        # Invalid formats
-        ('', None),
-        ('8:9:37', 'XXX Should give an exception'),
-        ('08:9:37', 'XXX Should give an exception'),
-        ('8:9', None),
-        ('8', None),
-
-        ]
-
-    for text, reference in l:
-        try:
-            value = TimeFromString(text, formats=('standard', 'iso'))
-        except:
-            if reference is None:
-                continue
-            else:
-                value = str(sys.exc_info()[1])
-        if str(value) != reference and \
-           not reference == 'ignore':
-            print 'Failed to parse "%s"' % text
-            print '  expected: %s' % (reference or '<exception>')
-            print '  parsed:   %s' % value
-        elif _debug:
-            print 'Parsed "%s" successfully' % text
-
-    et = DateTime.now()
-    print 'done. (after %f seconds)' % ((et-t).seconds)
-
-if __name__ == '__main__':
-    _test()
--- a/embedded/mx/DateTime/Timezone.py	Tue Apr 28 13:28:37 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,169 +0,0 @@
-# -*- coding: latin-1 -*-
-
-""" Timezone information.
-
-    XXX This module still has prototype status and is undocumented.
-
-    XXX Double check the offsets given in the zonetable below.
-
-    XXX Add TZ environment variable parsing functions. The REs are already
-        there.
-
-    Copyright (c) 1998-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
-    Copyright (c) 2000-2007, eGenix.com Software GmbH; mailto:info@egenix.com
-    See the documentation for further information on copyrights,
-    or contact the author. All Rights Reserved.
-
-"""
-import DateTime
-import re,string
-
-### REs
-
-# time zone parsing
-isozone = ('(?P<zone>[+-]\d\d:?(?:\d\d)?|Z)')
-zone = ('(?P<zone>[A-Z]+|[+-]\d\d?:?(?:\d\d)?)')
-zoneoffset = ('(?:'
-              '(?P<zonesign>[+-])?'
-              '(?P<hours>\d\d?)'
-              ':?'
-              '(?P<minutes>\d\d)?'
-              '(?P<extra>\d+)?'
-              ')'
-              )
-
-# TZ environment variable parsing
-dstswitchtime = ('(?P<hour>\d\d?):?'
-                 '(?P<minute>\d\d)?:?'
-                 '(?P<second>\d\d)?')
-dstswitch = ('(?:'
-              '(?P<doy>\d+)|'
-              '(?:J(?P<jdoy>\d+))|'
-              '(?:M(?P<month>\d+).(?P<week>\d+).(?P<day>\d+))'
-             ')'
-             '(?:/' + dstswitchtime + ')?'
-             )
-
-# XXX Doesn't work since re doesn't like multiple occurrences of
-#     group names.
-#tz = ('(?::(?P<filename>.+))|'
-#      '(?P<std>[A-Z]+)' + zoneoffset + 
-#      '(?:'
-#       '(?P<dst>[A-Z]+)' + zoneoffset + '?'+
-#       '(?:[;,]' + dstswitch + '[;,]' + dstswitch + ')'
-#      ')?'
-#      )
-
-# Compiled RE objects
-isozoneRE = re.compile(zone)
-zoneRE = re.compile(zone)
-zoneoffsetRE = re.compile(zoneoffset)
-#tzRE= re.compile(tz)
-
-### Time zone offset table
-#
-# The offset given here represent the difference between UTC and the
-# given time zone.
-#
-# Additions and corrections are always welcome :-)
-#
-# Note that some zone names are ambiguous, e.g. IST can refer to Irish
-# Summer Time, Indian Standard Time, Israel Standard Time. We've
-# usualy chosen meaning with the most wide-spread use.
-#
-zonetable = {
-              # Timezone abbreviations
-              # Std     Summer
-
-              # Standards
-              'UT':0,
-              'UTC':0,
-              'GMT':0,
-
-              # A few common timezone abbreviations
-              'CET':1,  'CEST':2, 'CETDST':2, # Central European
-              'MET':1,  'MEST':2, 'METDST':2, # Mean European
-              'MEZ':1,  'MESZ':2,             # Mitteleuropäische Zeit
-              'EET':2,  'EEST':3, 'EETDST':3, # Eastern Europe
-              'WET':0,  'WEST':1, 'WETDST':1, # Western Europe
-              'MSK':3,  'MSD':4,  # Moscow
-              'IST':5.5,          # India
-              'JST':9,            # Japan
-              'KST':9,            # Korea
-              'HKT':8,            # Hong Kong
-
-              # US time zones
-              'AST':-4, 'ADT':-3, # Atlantic
-              'EST':-5, 'EDT':-4, # Eastern
-              'CST':-6, 'CDT':-5, # Central
-              'MST':-7, 'MDT':-6, # Midwestern
-              'PST':-8, 'PDT':-7, # Pacific
-
-              # Australian time zones
-              'CAST':9.5, 'CADT':10.5, # Central
-              'EAST':10,  'EADT':11,   # Eastern
-              'WAST':8,   'WADT':9,    # Western
-              'SAST':9.5, 'SADT':10.5, # Southern
-
-              # US military time zones
-              'Z': 0,
-              'A': 1,
-              'B': 2,
-              'C': 3,
-              'D': 4,
-              'E': 5,
-              'F': 6,
-              'G': 7,
-              'H': 8,
-              'I': 9,
-              'K': 10,
-              'L': 11,
-              'M': 12,
-              'N':-1,
-              'O':-2,
-              'P':-3,
-              'Q':-4,
-              'R':-5,
-              'S':-6,
-              'T':-7,
-              'U':-8,
-              'V':-9,
-              'W':-10,
-              'X':-11,
-              'Y':-12
-              }    
-
-def utc_offset(zone,
-
-               atoi=string.atoi,zoneoffset=zoneoffsetRE,
-               zonetable=zonetable,zerooffset=DateTime.DateTimeDelta(0),
-               oneMinute=DateTime.oneMinute,upper=string.upper):
-
-    """ utc_offset(zonestring)
-
-        Return the UTC time zone offset as DateTimeDelta instance.
-
-        zone must be string and can either be given as +-HH:MM,
-        +-HHMM, +-HH numeric offset or as time zone
-        abbreviation. Daylight saving time must be encoded into the
-        zone offset.
-
-        Timezone abbreviations are treated case-insensitive.
-
-    """
-    if not zone:
-        return zerooffset
-    uzone = upper(zone)
-    if zonetable.has_key(uzone):
-        return zonetable[uzone]*DateTime.oneHour
-    offset = zoneoffset.match(zone)
-    if not offset:
-        raise ValueError,'wrong format or unknown time zone: "%s"' % zone
-    zonesign,hours,minutes,extra = offset.groups()
-    if extra:
-        raise ValueError,'illegal time zone offset: "%s"' % zone
-    offset = int(hours or 0) * 60 + int(minutes or 0)
-    if zonesign == '-':
-        offset = -offset
-    return offset*oneMinute
-
--- a/embedded/mx/DateTime/__init__.py	Tue Apr 28 13:28:37 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-""" mxDateTime - Date and time handling routines and types
-
-    Copyright (c) 1998-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
-    Copyright (c) 2000-2007, eGenix.com Software GmbH; mailto:info@egenix.com
-    See the documentation for further information on copyrights,
-    or contact the author. All Rights Reserved.
-"""
-from DateTime import *
-from DateTime import __version__
-
-## mock strptime implementation
-from datetime import datetime
-
-def strptime(datestr, formatstr, datetime=datetime):
-    """mocked strptime implementation"""
-    date = datetime.strptime(datestr, formatstr)
-    return DateTime(date.year, date.month, date.day,
-                    date.hour, date.minute, date.second)
-
-# don't expose datetime directly
-del datetime
--- a/embedded/mx/DateTime/mxDateTime_python.py	Tue Apr 28 13:28:37 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,614 +0,0 @@
-"""
-    Python implementation courtesy of Drew Csillag (StarMedia Network, Inc.)
-
-    This version has been somewhat modified by MAL. It is still fairly
-    rough though and not necessarily high performance... 
-
-    XXX Still needs testing and checkup !!!
-
-    WARNING: Using this file is only recommended if you really must
-    use it for some reason. It is not being actively maintained !
-
-"""
-
-__version__ = '1.2.0 [Python]'
-
-import time,types,exceptions,math
-
-### Errors
-
-class Error(exceptions.StandardError):
-    pass
-
-class RangeError(Error):
-    pass
-
-### Constants (internal use only)
-
-month_offset=(
-    (0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365),
-    (0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366),
-    )
-
-days_in_month=(
-    (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31),
-    (31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31),
-    )
-
-### Helpers
-
-def _IS_LEAPYEAR(d):
-    return ((d.year % 4 == 0)
-            and (
-                (d.year % 100 != 0)
-                or (d.year % 400 == 0)
-                )
-            )
-
-def _YEAROFFSET(d):
-    return (
-        (d.year - 1) * 365
-        + (d.year - 1) / 4
-        - (d.year - 1) / 100
-        + (d.year - 1) / 400
-        )
-
-class _EmptyClass:
-    pass
-
-def createEmptyObject(Class,
-                      _EmptyClass=_EmptyClass):
-
-    o = _EmptyClass()
-    o.__class__ = Class
-    return o
-
-### DateTime class
-
-class DateTime:
-
-    def __init__(self, year, month=1, day=1, hour=0, minute=0, second=0.0):
-
-        second=1.0 * second
-        if month <= 0:
-            raise RangeError, "year out of range (>0)"
-
-        #calculate absolute date
-        leap = (year % 4 == 0) and ((year % 100 != 0) or (year % 400 == 0))
-
-        #Negative values indicate days relative to the years end
-        if month < 0:
-            month = month + 13 
-
-        if not (month >= 1 and month <= 12):
-            raise RangeError, "month out of range (1-12)"
-
-        #Negative values indicate days relative to the months end
-        if (day < 0):
-            day = day + days_in_month[leap][month - 1] + 1;
-
-        if not (day >= 1 and day <= days_in_month[leap][month - 1]):
-            raise RangeError, "day out of range"
-
-        year = year - 1
-        yearoffset = year * 365 + year / 4 - year / 100 + year / 400
-        year = year + 1
-        absdate = day + month_offset[leap][month - 1] + yearoffset;
-
-        self.absdate = absdate
-        self.year = year
-        self.month = month
-        self.day = day
-        self.day_of_week = (absdate - 1) % 7
-        self.day_of_year = absdate - yearoffset
-        self.days_in_month = days_in_month[leap][month - 1]
-        comdate = absdate - 693594
-
-        if not (hour >=0 and hour <= 23):
-            raise RangeError, "hour out of range (0-23)"
-        if not (minute >= 0 and minute <= 59):
-            raise RangeError, "minute out of range (0-59)"
-        if not (second >= 0.0 and
-                (second < 60.0 or 
-                 (hour == 23 and minute == 59 and second < 61.0))):
-            raise RangeError, "second out of range (0.0 - <60.0; <61.0 for 23:59)"
-
-        self.abstime = (hour * 3600 + minute * 60) + second
-        self.hour = hour
-        self.minute = minute
-        self.second = second
-        self.dst = -1
-        self.tz = "???"
-        self.is_leapyear = leap
-        self.yearoffset = yearoffset
-        self.iso_week = (self.year, self.day, self.day_of_week)
-
-        if comdate < 0.0:
-            comdate = comdate - self.abstime / 86400.0
-        else:
-            comdate = comdate + self.abstime / 86400.0
-
-        self.comdate = comdate
-
-    def COMDate(self):
-        return self.comdate
-    
-    def __str__(self):
-        return "%04d-%02d-%02d %02d:%02d:%05.2f" % (
-            self.year, self.month, self.day, self.hour, self.minute,
-            self.second)
-    
-    def __getattr__(self, attr):
-        if attr == 'mjd':
-            return (self - mjd0).days
-        elif attr == 'jdn':
-            return (self - jdn0).days
-        elif attr == 'tjd':
-            return (self - jdn0).days % 10000
-        elif attr == 'tjd_myriad':
-            return int((self - jdn0).days) / 10000 + 240
-        elif attr == 'absdays':
-            return self.absdate - 1 + self.abstime / 86400.0
-        else:
-            try:
-                return self.__dict__[attr]
-            except:
-                raise AttributeError, attr
-
-    def __mul__(self, other):
-        raise TypeError, "bad operand type(s) for *"
-
-    def __div__(self, other):
-        raise TypeError, "bad operand type(s) for /"
-    
-    def strftime(self, format_string="%c"):
-        "localtime([seconds]) -> (tm_year,tm_mon,tm_day,tm_hour,tm_min,tm_sec,tm_wday,tm_yday,tm_isdst)"
-        # The map prevents a deprecation warning on Python 2.5.1 (Mac)
-        # DeprecationWarning: integer argument expected, got float
-        items = [int(item) for item in self.tuple()]
-        return time.strftime(format_string, items)
-
-    # Alias
-    Format = strftime
-    
-    def tuple(self):
-        return (self.year, self.month, self.day, self.hour, self.minute,
-                self.second, self.day_of_week, self.day_of_year, -1)
-        #return time.localtime(self.ticks())
-
-    def absvalues(self):
-        return self.absdate, self.abstime
-    
-    def __float__(self):
-        return self.ticks()
-
-    def __int__(self):
-        return int(self.ticks)
-    
-    def ticks(self, offset=0.0, dst=-1):
-        tticks=time.mktime(self.year, self.month, self.day, self.hour,
-                           self.minute, self.second, self.day_of_week, 0, dst)
-        if tticks == -1:
-            raise OverflowError, "cannot convert value to a time value"
-        ticks = (1.0*tticks) + (self.abstime - int(self.abstime)) - offset
-        return ticks
-
-    def gmticks(self, offset=0.0):
-        from mx.DateTime import tz_offset
-        return (self-tz_offset(self)).ticks()
-
-    def gmtoffset(self):
-        gmtime = DateTime(*time.gmtime()[:6])
-        return - (now() - gmtime)
-    
-    def __repr__(self):
-        return "<DateTime object for '%d-%02d-%02d %02d:%02d:%05.2f' at %x>"% (
-            self.year, self.month, self.day, self.hour, self.minute,
-            self.second, id(self))
-
-    def __cmp__(self, other,
-                cmp=cmp):
-
-        if isinstance(other,DateTime):
-            cmpdate = cmp(self.absdate,other.absdate)
-            if cmpdate == 0:
-                return cmp(self.abstime,other.abstime)
-            else:
-                return cmpdate
-        elif type(other) == types.NoneType:
-            return -1
-        elif type(other) == types.StringType:
-            return -1
-        elif type(other) in (types.FloatType, types.LongType, types.IntType):
-            return 1
-        return -1
-
-    def __hash__(self):
-        return hash(self.tuple())
-    
-    def __add__(self, other):
-        abstime=self.abstime
-        absdate=self.absdate
-
-        didadd=0
-        
-        if type(other) == types.InstanceType:
-            if other.__class__ == DateTimeDelta:
-                abstime = abstime + other.seconds
-                didadd=1
-            elif other.__class__ == DateTime:
-                raise TypeError, "DateTime + DateTime is not supported"
-            else:
-                return other.__class__.__radd__(other, self)
-            
-        elif type(other) == types.IntType or type(other) == types.FloatType:
-            abstime = abstime + other * 86400.0
-            didadd=1
-
-        if not didadd:
-            raise TypeError, "cannot add these two types"
-
-        if abstime >= 86400.0:
-            days = abstime / 86400.0
-            absdate = absdate + days
-            abstime = abstime - (86400.0 * int(days))
-            #print "absdate, abstime = ", absdate, abstime
-        elif abstime < 0.0:
-            days = int(((-abstime - 1) / 86400.0)) + 1
-            #days = int(-abstime / 86400.0)
-            absdate = absdate - days
-            abstime = abstime + 86400.0 * int(days)
-
-        if absdate < 1:
-            raise RangeError, "underflow while adding"
-
-        return DateTimeFromAbsDateTime(absdate, abstime)
-
-    def __radd__(self, other):
-        return DateTime.__add__(other, self)
-    
-    def __sub__(self, other):
-        abstime=self.abstime
-        absdate=self.absdate
-
-        didsub=0
-        if type(other) == types.InstanceType:
-            if other.__class__ == DateTimeDelta:
-                abstime = abstime - other.seconds
-                didsub = 1
-            elif other.__class__ == DateTime:
-                absdate = absdate - other.absdate
-                abstime = abstime - other.abstime
-                return DateTimeDelta(absdate,0.0,0.0,abstime)
-            else:
-                return other.__rsub__(self)
-
-        elif type(other) == types.IntType or type(other) == types.FloatType:
-            abstime = abstime - other * 86400.0;
-            didsub=1
-
-        if not didsub:
-            raise TypeError, "cannot subtract these two types"
-
-        if abstime >= 86400.0:
-            days = abstime / 86400.0
-            absdate = absdate + days
-            abstime = abstime - (86400.0 * days)
-            #print "absdate, abstime = ", absdate, abstime
-        elif abstime < 0.0:
-            #print "abstime < 0"
-            days = int( ((-abstime - 1) / 86400.0) + 1)
-            #days = -abstime / 86400.0
-            absdate = absdate - int(days)
-            abstime = (1.0*abstime) + (86400.0 * days)
-            #print "absdate, abstime", absdate, abstime
-        if absdate < 1:
-            raise RangeError, "underflow while adding"
-
-        return DateTimeFromAbsDateTime(absdate, abstime)
-
-# Constants
-mjd0 = DateTime(1858, 11, 17)
-jdn0 = DateTime(-4713, 1, 1, 12, 0, 0.0)
-
-# Other DateTime constructors
-
-def DateTimeFromCOMDate(comdate):
-
-    absdate = int(comdate)
-    abstime = (comdate - float(absdate)) * 86400.0
-    if abstime < 0.0:
-        abstime = -abstime
-    absdate = absdate + 693594;
-    dt = DateTimeFromAbsDateTime(absdate, abstime)
-    dt.comdate = comdate
-    return dt
-    
-def DateTimeFromAbsDateTime(absdate, abstime):
-
-    # Create the object without calling its default constructor
-    dt = createEmptyObject(DateTime)
-
-    # Init. the object
-    abstime=1.0 * abstime
-    if abstime < 0 and abstime > -0.001: abstime = 0.0
-    if not (absdate > 0):
-        raise RangeError, "absdate out of range (>0)"
-    if not (abstime >= 0.0 and abstime <= 86400.0):
-        raise RangeError, "abstime out of range (0.0 - 86400.0) <%s>" % abstime
-
-    dt.absdate=absdate
-    dt.abstime=abstime
-
-    #calculate com date
-    comdate = 1.0 * (dt.absdate - 693594)
-    if comdate < 0.0:
-        comdate = comdate - dt.abstime / 86400.0
-    else:
-        comdate = comdate + dt.abstime / 86400.0
-    dt.comdate = comdate
-
-    #calculate the date
-    #print "absdate=", absdate
-    year = int((1.0 * absdate) / 365.2425)
-
-    #newApproximation:
-    while 1:
-        #print "year=", year
-        yearoffset = year * 365 + year / 4 - year / 100 + year / 400
-        #print "yearoffset=", yearoffset
-        #print "absdate=", absdate
-        if yearoffset >= absdate:
-            year = year - 1
-            #print "year = ", year
-            continue #goto newApproximation
-
-        year = year + 1
-        leap = (year % 4 == 0) and ((year % 100 != 0) or (year % 400 == 0))
-        dayoffset = absdate - yearoffset
-        #print "dayoffset=", dayoffset
-        if dayoffset > 365 and leap == 0:
-            #print "dayoffset=", dayoffset
-            continue #goto newApproximation
-
-        monthoffset = month_offset[leap]
-        for month in range(1, 13):
-            if monthoffset[month] >= dayoffset:
-                break
-        dt.year = year
-        dt.month = month
-        dt.day = dayoffset - month_offset[leap][month-1]
-        dt.day_of_week = (dt.absdate - 1) % 7
-        dt.day_of_year = dayoffset
-        break
-    
-    #calculate the time
-    inttime = int(abstime)
-    hour = inttime / 3600
-    minute = (inttime % 3600) / 60
-    second = abstime - 1.0 * (hour*3600 + minute*60)
-    dt.hour = hour;
-    dt.minute = minute;
-    dt.second = second;
-    dt.days_in_month = days_in_month[leap][month - 1]
-    dt.dst = -1
-    dt.tz = "???"
-    dt.is_leapyear = leap
-    dt.yearoffset = yearoffset
-    return dt
-
-def now(
-        time=time.time,float=float,localtime=time.localtime,
-        round=round,int=int,DateTime=DateTime,floor=math.floor):
-    ticks = time()
-    Y,M,D,h,m,s = localtime(ticks)[:6]
-    s = s + (ticks - floor(ticks))
-    return DateTime(Y,M,D,h,m,s)
-
-def utc(
-        time=time.time,float=float,gmtime=time.gmtime,
-        round=round,int=int,DateTime=DateTime,floor=math.floor):
-
-    ticks = time()
-    Y,M,D,h,m,s = gmtime(ticks)[:6]
-    s = s + (ticks - floor(ticks))
-    return DateTime(Y,M,D,h,m,s)
-
-# Aliases
-Date = Timestamp = DateTime
-
-# XXX Calendars are not supported:
-def notSupported(*args,**kws):
-    raise Error,'calendars are not supported by the Python version of mxDateTime'
-JulianDateTime = notSupported
-
-### DateTimeDelta class
-               
-class DateTimeDelta:
-
-    def __init__(self, days=0, hours=0, minutes=0, seconds=0):
-
-        seconds = seconds + (days * 86400.0 + hours * 3600.0 + minutes * 60.0)
-        self.seconds = seconds
-        if seconds < 0.0:
-            seconds = -seconds
-        day = long(seconds / 86400.0)
-        seconds = seconds - (86400.0 * day)
-        wholeseconds = int(seconds)
-        hour = wholeseconds / 3600
-        minute = (wholeseconds % 3600) / 60
-        second = seconds - (hour * 3600.0 + minute * 60.0)
-        self.day = day
-        self.hour = hour
-        self.minute = minute
-        self.second = second
-        seconds=self.seconds
-        self.minutes = seconds / 60.0
-        self.hours = seconds / 3600.0
-        self.days = seconds / 86400.0
-
-    def __str__(self):
-        if self.day != 0:
-            if self.seconds >= 0.0:
-                r="%s:%02d:%02d:%05.2f" % (
-                    self.day, self.hour, self.minute, self.second)
-            else:
-                r="-%s:%02d:%02d:%05.2f" % (
-                    self.day, self.hour, self.minute, self.second)
-        else:
-            if self.seconds >= 0.0:
-                r="%02d:%02d:%05.2f" % (self.hour, self.minute, self.second)
-            else:
-                r="-%02d:%02d:%05.2f" % (self.hour, self.minute, self.second)
-        return r
-            
-    def absvalues(self):
-        days=self.seconds / 86400
-        seconds=self.seconds - (days * 86400.0)
-        return days, seconds
-
-    def tuple(self):
-        return (self.day, self.hour, self.minute, self.second)
-
-    def strftime(self, format_string):
-        raise NotImplementedError
-    
-    def __int__(self):
-        return int(self.seconds)
-
-    def __float__(self):
-        return self.seconds
-    
-    def __cmp__(self, other, accuracy=0.0):
-        if (type(other) == types.InstanceType
-            and other.__class__ == DateTimeDelta):
-
-            diff=self.seconds - other.seconds
-            if abs(diff) > accuracy:
-                if diff > 0: return 1
-                return -1
-            
-        elif type(other) == types.FloatType:
-            diff=self.seconds - other
-            if abs(diff) > accuracy:
-                if diff > 0: return 1
-                return -1
-            
-        elif type(other) == types.IntType:
-            diff=self.seconds - other
-            if abs(diff) > accuracy:
-                if diff > 0: return 1
-                return -1
-            
-        return 0
-    
-    def __getattr__(self, attr):
-        seconds=self.__dict__['seconds']
-        if attr in ('hour', 'minute', 'second', 'day'):
-            if seconds >= 0.0:
-                return self.__dict__[attr]
-            else:
-                return -self.__dict__[attr]
-        else:
-            try:
-                return self.__dict__[attr]
-            except:
-                raise AttributeError, attr
-
-    def __div__(self, other):
-        if type(other) in (types.IntType, types.FloatType):
-            return DateTimeDelta(0.0,0.0,0.0,self.seconds / other)
-        elif (type(other) == types.InstanceType
-              and isinstance(other,DateTimeDelta)):
-            return DateTimeDelta(0.0,0.0,0.0,self.seconds / other.seconds)
-        raise TypeError, "bad operand types for /"
-    
-    def __mul__(self, other):
-        if type(other) == types.IntType or type(other) == types.FloatType:
-            return DateTimeDelta(0.0,0.0,0.0,self.seconds * other)
-        else:
-            #print "type", type(other)
-            raise TypeError, "cannot multiply these two types"
-
-    def __rmul__(self, other):
-        return self.__mul__(other)
-    
-    def __neg__(self):
-        return DateTimeDelta(0.0,0.0,0.0,-self.seconds)
-        
-    def __repr__(self):
-        if self.day != 0:
-            if self.seconds >= 0.0:
-                strval="%s:%02d:%02d:%05.2f" % (self.day, self.hour,
-                                                 self.minute, self.second)
-            else:
-                strval="-%s:%02d:%02d:%05.2f" % (self.day, self.hour,
-                                                  self.minute, self.second)
-        else:
-            if self.seconds >= 0.0:
-                strval="%02d:%02d:%05.2f" % (self.hour, self.minute,
-                                            self.second)
-            else:
-                strval="-%02d:%02d:%05.2f" % (self.hour, self.minute,
-                                             self.second)
-        return "<DateTimeDelta object for '%s' at %x>" % (strval, id(self))
-    
-    def __abs__(self):
-        if self.seconds < 0:
-            return -self
-        return self
-
-    def __nonzero__(self):
-        return self.seconds != 0.0
-    
-    def __add__(self, other):
-        if type(other) == types.InstanceType:
-            if isinstance(other,DateTime):
-                return other + self
-            elif isinstance(other,DateTimeDelta):
-                return DateTimeDelta(0.0,0.0,0.0,self.seconds + other.seconds)
-
-    # What about __radd__ ?
-        
-# Other DateTimeDelta constructors
-
-def TimeDelta(hour=0.0, minute=0.0, second=0.0):
-    return DateTimeDelta(0.0, hours, minutes, seconds)
-
-Time=TimeDelta
-
-def DateTimeDeltaFromSeconds(seconds):
-    return DateTimeDelta(0.0,0.0,0.0,seconds)
-
-def DateTimeDeltaFromDays(days):
-    return DateTimeDelta(days)
-
-### Types
-
-DateTimeType = DateTime
-DateTimeDeltaType = DateTimeDelta
-
-### Functions
-
-def cmp(a,b,acc):
-
-    if isinstance(a,DateTime) and isinstance(b,DateTime):
-        diff = a.absdays - b.absdays
-        if (diff >= 0 and diff <= acc) or (diff < 0 and -diff <= acc):
-            return 0
-        elif diff < 0:
-            return 1
-        else:
-            return -1
-
-    elif isinstance(a,DateTimeDelta) and isinstance(b,DateTimeDelta):
-        diff = a.days - b.days
-        if (diff >= 0 and diff <= acc) or (diff < 0 and -diff <= acc):
-            return 0
-        elif diff < 0:
-            return 1
-        else:
-            return -1
-
-    else:
-        raise TypeError,"objects must be DateTime[Delta] instances"
--- a/entities/__init__.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/entities/__init__.py	Tue Apr 28 19:12:52 2009 +0200
@@ -23,7 +23,7 @@
     """an entity instance has e_schema automagically set on the class and
     instances have access to their issuing cursor
     """
-    id = 'Any'                    
+    id = 'Any'
     __implements__ = (IBreadCrumbs, IFeed)
 
     @classmethod
@@ -38,7 +38,7 @@
         usercls.id = etype
         usercls.__initialize__()
         return usercls
-    
+
     fetch_attrs = ('modification_date',)
     @classmethod
     def fetch_order(cls, attr, var):
@@ -46,7 +46,7 @@
         this type are fetched
         """
         return cls.fetch_unrelated_order(attr, var)
-    
+
     @classmethod
     def fetch_unrelated_order(cls, attr, var):
         """class method used to control sort order when multiple entities of
@@ -58,7 +58,7 @@
         return None
 
     @classmethod
-    def __initialize__(cls): 
+    def __initialize__(cls):
         super(ANYENTITY, cls).__initialize__() # XXX
         # set a default_ATTR method for rich text format fields
         # XXX move this away once the old widgets have been dropped!
@@ -66,7 +66,7 @@
         for metaattr, (metadata, attr) in eschema.meta_attributes().iteritems():
             if metadata == 'format' and not hasattr(cls, 'default_%s' % metaattr):
                 setattr(cls, 'default_%s' % metaattr, cls._default_format)
-    
+
     # meta data api ###########################################################
 
     def dc_title(self):
@@ -84,7 +84,7 @@
     def dc_long_title(self):
         """return a more detailled title for this entity"""
         return self.dc_title()
-    
+
     def dc_description(self, format='text/plain'):
         """return a suitable description for this entity"""
         if self.e_schema.has_subject_relation('description'):
@@ -121,7 +121,7 @@
                                  'internationalizable'):
                 return self.req._(self.req.user.property_value('ui.language'))
         return self.req._(self.vreg.property_value('ui.language'))
-        
+
     @property
     def creator(self):
         """return the CWUser entity which has created this entity, or None if
@@ -157,9 +157,9 @@
 
     def rss_feed_url(self):
         return self.absolute_url(vid='rss')
-    
+
     # abstractions making the whole things (well, some at least) working ######
-        
+
     def sortvalue(self, rtype=None):
         """return a value which can be used to sort this entity or given
         entity's attribute
@@ -172,7 +172,7 @@
             return self.printable_value(rtype, format='text/plain').lower()
         return value
 
-    # edition helper functions ################################################    
+    # edition helper functions ################################################
 
     def linked_to(self, rtype, target, remove=True):
         """if entity should be linked to another using __linkto form param for
@@ -200,9 +200,9 @@
                 linkedto.append(typed_eid(eid))
         self.__linkto[(rtype, target)] = linkedto
         return linkedto
-    
+
     # edit controller callbacks ###############################################
-    
+
     def after_deletion_path(self):
         """return (path, parameters) which should be used as redirect
         information when this entity is being deleted
@@ -216,20 +216,20 @@
         Do nothing by default.
         """
         pass
-    
+
     # server side helpers #####################################################
-    
+
     def notification_references(self, view):
         """used to control References field of email send on notification
         for this entity. `view` is the notification view.
-        
+
         Should return a list of eids which can be used to generate message ids
         of previously sent email
         """
         return ()
-            
+
     # XXX deprecates, may be killed once old widgets system is gone ###########
-    
+
     @classmethod
     def get_widget(cls, rschema, x='subject'):
         """return a widget to view or edit a relation
@@ -258,20 +258,20 @@
     def object_relation_vocabulary(self, rtype, limit):
         from cubicweb.web.form import EntityFieldsForm
         return EntityFieldsForm(self.req, None, entity=self).object_relation_vocabulary(rtype, limit)
-    
+
     @obsolete('use AutomaticEntityForm.[e]relations_by_category')
     def relations_by_category(self, categories=None, permission=None):
-        from cubicweb.web.views.editforms import AutomaticEntityForm
+        from cubicweb.web.views.autoform import AutomaticEntityForm
         return AutomaticEntityForm.erelations_by_category(self, categories, permission)
 
     @obsolete('use AutomaticEntityForm.[e]srelations_by_category')
     def srelations_by_category(self, categories=None, permission=None):
-        from cubicweb.web.views.editforms import AutomaticEntityForm
+        from cubicweb.web.views.autoform import AutomaticEntityForm
         return AutomaticEntityForm.esrelations_by_category(self, categories, permission)
-    
+
     def _default_format(self):
         return self.req.property_value('ui.default-text-format')
-                
+
     def attribute_values(self, attrname):
         if self.has_eid() or attrname in self:
             try:
--- a/entity.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/entity.py	Tue Apr 28 19:12:52 2009 +0200
@@ -41,30 +41,26 @@
     return '1'
 
 
-MODE_TAGS = set(('link', 'create'))
-CATEGORY_TAGS = set(('primary', 'secondary', 'generic', 'generated')) # , 'metadata'))
+_MODE_TAGS = set(('link', 'create'))
+_CATEGORY_TAGS = set(('primary', 'secondary', 'generic', 'generated')) # , 'metadata'))
 
 try:
-    from cubicweb.web import formwidgets
+    from cubicweb.web import formwidgets, uicfg
     from cubicweb.web.views.editforms import AutomaticEntityForm
-    from cubicweb.web.views.boxes import EditBox
 
-    def dispatch_rtags(tags, rtype, role, stype, otype):
+    def _dispatch_rtags(tags, rtype, role, stype, otype):
         for tag in tags:
-            if tag in MODE_TAGS:
-                EditBox.rmode.set_rtag(tag, rtype, role, stype, otype)
-            elif tag in CATEGORY_TAGS:
-                AutomaticEntityForm.rcategories.set_rtag(tag, rtype, role, stype, otype)
+            if tag in _MODE_TAGS:
+                uicfg.rmode.set_rtag(tag, rtype, role, stype, otype)
+            elif tag in _CATEGORY_TAGS:
+                uicfg.rcategories.set_rtag(tag, rtype, role, stype, otype)
             elif tag == 'inlineview':
-                AutomaticEntityForm.rinlined.set_rtag(True, rtype, role, stype, otype)
+                uicfg.rinlined.set_rtag(True, rtype, role, stype, otype)
             else:
                 raise ValueError(tag)
 
 except ImportError:
-    AutomaticEntityForm = None
-
-    def dispatch_rtags(*args):
-        pass
+    _dispatch_rtags = None
 
 def _get_etype(bases, classdict):
     try:
@@ -87,14 +83,14 @@
             except AttributeError:
                 continue
 
-class metaentity(type):
+class _metaentity(type):
     """this metaclass sets the relation tags on the entity class
     and deals with the `widgets` attribute
     """
     def __new__(mcs, name, bases, classdict):
         # collect baseclass' rtags
         etype = _get_etype(bases, classdict)
-        if etype and AutomaticEntityForm is not None:
+        if etype and _dispatch_rtags is not None:
             for name, rtags in _get_defs('__rtags__', name, bases, classdict):
                 warn('%s: __rtags__ is deprecated' % name, DeprecationWarning)
                 for relation, tags in rtags.iteritems():
@@ -103,23 +99,23 @@
                         tags = (tags,)
                     # relation must become a 3-uple (rtype, targettype, role)
                     if isinstance(relation, basestring):
-                        dispatch_rtags(tags, relation, 'subject', etype, '*')
-                        dispatch_rtags(tags, relation, 'object', '*', etype)
+                        _dispatch_rtags(tags, relation, 'subject', etype, '*')
+                        _dispatch_rtags(tags, relation, 'object', '*', etype)
                     elif len(relation) == 1: # useful ?
-                        dispatch_rtags(tags, relation[0], 'subject', etype, '*')
-                        dispatch_rtags(tags, relation[0], 'object', '*', etype)
+                        _dispatch_rtags(tags, relation[0], 'subject', etype, '*')
+                        _dispatch_rtags(tags, relation[0], 'object', '*', etype)
                     elif len(relation) == 2:
                         rtype, ttype = relation
                         ttype = bw_normalize_etype(ttype) # XXX bw compat
-                        dispatch_rtags(tags, rtype, 'subject', etype, ttype)
-                        dispatch_rtags(tags, rtype, 'object', ttype, etype)
+                        _dispatch_rtags(tags, rtype, 'subject', etype, ttype)
+                        _dispatch_rtags(tags, rtype, 'object', ttype, etype)
                     elif len(relation) == 3:
                         rtype, ttype, role = relation
                         ttype = bw_normalize_etype(ttype)
                         if role == 'subject':
-                            dispatch_rtags(tags, rtype, 'subject', etype, ttype)
+                            _dispatch_rtags(tags, rtype, 'subject', etype, ttype)
                         else:
-                            dispatch_rtags(tags, rtype, 'object', ttype, etype)
+                            _dispatch_rtags(tags, rtype, 'object', ttype, etype)
                     else:
                         raise ValueError('bad rtag definition (%r)' % (relation,))
             for name, widgets in _get_defs('widgets', name, bases, classdict):
@@ -132,7 +128,7 @@
                         wdgname = 'TextInput'
                     widget = getattr(formwidgets, wdgname)
                     AutomaticEntityForm.rwidgets.set_rtag(wdgname, rtype, 'subject', etype)
-        return super(metaentity, mcs).__new__(mcs, name, bases, classdict)
+        return super(_metaentity, mcs).__new__(mcs, name, bases, classdict)
 
 
 class Entity(AppRsetObject, dict):
@@ -158,7 +154,7 @@
                          as composite relations or relations that have '?1' as object
                          cardinality
     """
-    __metaclass__ = metaentity
+    __metaclass__ = _metaentity
     __registry__ = 'etypes'
     __select__ = yes()
 
--- a/i18n/en.po	Tue Apr 28 13:28:37 2009 +0200
+++ b/i18n/en.po	Tue Apr 28 19:12:52 2009 +0200
@@ -196,36 +196,11 @@
 msgid "Bytes_plural"
 msgstr "Bytes"
 
-msgid "Card"
-msgstr "Card"
-
-msgid "Card_plural"
-msgstr "Cards"
-
-msgid "Date"
-msgstr "Date"
-
-msgid "Date_plural"
-msgstr "Dates"
-
-msgid "Datetime"
-msgstr "Date and time"
-
-msgid "Datetime_plural"
-msgstr "Dates and times"
-
-#, python-format
-msgid "Debug level set to %s"
-msgstr ""
-
-msgid "Decimal"
-msgstr "Decimal number"
-
-msgid "Decimal_plural"
-msgstr "Decimal numbers"
-
-msgid "Do you want to delete the following element(s) ?"
-msgstr ""
+msgid "CWAttribute"
+msgstr "Attribute"
+
+msgid "CWAttribute_plural"
+msgstr "Attributes"
 
 msgid "CWCache"
 msgstr ""
@@ -251,24 +226,12 @@
 msgid "CWEType_plural"
 msgstr "Entity types"
 
-msgid "CWAttribute"
-msgstr "Attribute"
-
-msgid "CWAttribute_plural"
-msgstr "Attributes"
-
 msgid "CWGroup"
 msgstr "Group"
 
 msgid "CWGroup_plural"
 msgstr "Groups"
 
-msgid "CWRelation"
-msgstr "Relation"
-
-msgid "CWRelation_plural"
-msgstr "Relations"
-
 msgid "CWPermission"
 msgstr "Permission"
 
@@ -287,13 +250,41 @@
 msgid "CWRType_plural"
 msgstr "Relation types"
 
+msgid "CWRelation"
+msgstr "Relation"
+
+msgid "CWRelation_plural"
+msgstr "Relations"
+
 msgid "CWUser"
 msgstr "User"
 
 msgid "CWUser_plural"
 msgstr "Users"
 
-msgid "Email body: "
+msgid "Date"
+msgstr "Date"
+
+msgid "Date_plural"
+msgstr "Dates"
+
+msgid "Datetime"
+msgstr "Date and time"
+
+msgid "Datetime_plural"
+msgstr "Dates and times"
+
+#, python-format
+msgid "Debug level set to %s"
+msgstr ""
+
+msgid "Decimal"
+msgstr "Decimal number"
+
+msgid "Decimal_plural"
+msgstr "Decimal numbers"
+
+msgid "Do you want to delete the following element(s) ?"
 msgstr ""
 
 msgid "EmailAddress"
@@ -314,7 +305,7 @@
 msgid "Float_plural"
 msgstr "Floats"
 
-msgid "From: "
+msgid "From:"
 msgstr ""
 
 msgid "Int"
@@ -332,8 +323,8 @@
 msgid "New Bookmark"
 msgstr "New bookmark"
 
-msgid "New Card"
-msgstr "New card"
+msgid "New CWAttribute"
+msgstr "New attribute"
 
 msgid "New CWCache"
 msgstr ""
@@ -347,15 +338,9 @@
 msgid "New CWEType"
 msgstr "New entity type"
 
-msgid "New CWAttribute"
-msgstr "New attribute"
-
 msgid "New CWGroup"
 msgstr "New group"
 
-msgid "New CWRelation"
-msgstr "New relation"
-
 msgid "New CWPermission"
 msgstr "New permission"
 
@@ -365,6 +350,9 @@
 msgid "New CWRType"
 msgstr "New relation type"
 
+msgid "New CWRelation"
+msgstr "New relation"
+
 msgid "New CWUser"
 msgstr "New user"
 
@@ -401,16 +389,13 @@
 msgid "Please note that this is only a shallow copy"
 msgstr ""
 
-msgid "Problem occured"
-msgstr ""
-
 msgid "RQLExpression"
 msgstr "RQL expression"
 
 msgid "RQLExpression_plural"
 msgstr "RQL expressions"
 
-msgid "Recipients: "
+msgid "Recipients:"
 msgstr ""
 
 msgid "Relations"
@@ -444,7 +429,7 @@
 msgid "String_plural"
 msgstr "Strings"
 
-msgid "Subject: "
+msgid "Subject:"
 msgstr ""
 
 msgid "Submit bug report"
@@ -471,8 +456,8 @@
 msgid "This Bookmark"
 msgstr "This bookmark"
 
-msgid "This Card"
-msgstr "This card"
+msgid "This CWAttribute"
+msgstr "This attribute"
 
 msgid "This CWCache"
 msgstr ""
@@ -486,15 +471,9 @@
 msgid "This CWEType"
 msgstr "This entity type"
 
-msgid "This CWAttribute"
-msgstr "This attribute"
-
 msgid "This CWGroup"
 msgstr "This group"
 
-msgid "This CWRelation"
-msgstr "This relation"
-
 msgid "This CWPermission"
 msgstr "This permission"
 
@@ -504,6 +483,9 @@
 msgid "This CWRType"
 msgstr "This relation type"
 
+msgid "This CWRelation"
+msgstr "This relation"
+
 msgid "This CWUser"
 msgstr "This user"
 
@@ -596,11 +578,6 @@
 msgstr ""
 
 msgid ""
-"a card is a textual content used as documentation, reference, procedure "
-"reminder"
-msgstr ""
-
-msgid ""
 "a simple cache entity characterized by a name and a validity date. The "
 "target application is responsible for updating timestamp when necessary to "
 "invalidate the cache (typically in hooks). Also, checkout the AppRsetObject."
@@ -682,6 +659,12 @@
 msgid "actions_manage_description"
 msgstr ""
 
+msgid "actions_managepermission"
+msgstr ""
+
+msgid "actions_managepermission_description"
+msgstr ""
+
 msgid "actions_muledit"
 msgstr "modify all"
 
@@ -754,6 +737,12 @@
 msgid "add Bookmark bookmarked_by CWUser object"
 msgstr "bookmark"
 
+msgid "add CWAttribute constrained_by CWConstraint subject"
+msgstr "constraint"
+
+msgid "add CWAttribute relation_type CWRType object"
+msgstr "attribute definition"
+
 msgid "add CWEType add_permission RQLExpression subject"
 msgstr "rql expression for the add permission"
 
@@ -766,18 +755,6 @@
 msgid "add CWEType update_permission RQLExpression subject"
 msgstr "rql expression for the update permission"
 
-msgid "add CWAttribute constrained_by CWConstraint subject"
-msgstr "constraint"
-
-msgid "add CWAttribute relation_type CWRType object"
-msgstr "attribute definition"
-
-msgid "add CWRelation constrained_by CWConstraint subject"
-msgstr "constraint"
-
-msgid "add CWRelation relation_type CWRType object"
-msgstr "relation definition"
-
 msgid "add CWProperty for_user CWUser object"
 msgstr "property"
 
@@ -790,6 +767,12 @@
 msgid "add CWRType read_permission RQLExpression subject"
 msgstr "rql expression for the read permission"
 
+msgid "add CWRelation constrained_by CWConstraint subject"
+msgstr "constraint"
+
+msgid "add CWRelation relation_type CWRType object"
+msgstr "relation definition"
+
 msgid "add CWUser in_group CWGroup object"
 msgstr "user"
 
@@ -820,8 +803,8 @@
 msgid "add a Bookmark"
 msgstr "add a bookmark"
 
-msgid "add a Card"
-msgstr "add a card"
+msgid "add a CWAttribute"
+msgstr "add an attribute"
 
 msgid "add a CWCache"
 msgstr ""
@@ -835,15 +818,9 @@
 msgid "add a CWEType"
 msgstr "add an entity type"
 
-msgid "add a CWAttribute"
-msgstr "add an attribute"
-
 msgid "add a CWGroup"
 msgstr "add a group"
 
-msgid "add a CWRelation"
-msgstr "add a relation"
-
 msgid "add a CWPermission"
 msgstr "add a permission"
 
@@ -853,6 +830,9 @@
 msgid "add a CWRType"
 msgstr "add a relation type"
 
+msgid "add a CWRelation"
+msgstr "add a relation"
+
 msgid "add a CWUser"
 msgstr "add a user"
 
@@ -916,21 +896,6 @@
 msgid "allowed_transition_object"
 msgstr "incoming states"
 
-msgid "am/pm calendar (month)"
-msgstr ""
-
-msgid "am/pm calendar (semester)"
-msgstr ""
-
-msgid "am/pm calendar (week)"
-msgstr ""
-
-msgid "am/pm calendar (year)"
-msgstr ""
-
-msgid "an abstract for this card"
-msgstr ""
-
 msgid "an electronic mail address associated to a short alias"
 msgstr ""
 
@@ -1079,18 +1044,6 @@
 msgid "calendar"
 msgstr ""
 
-msgid "calendar (month)"
-msgstr ""
-
-msgid "calendar (semester)"
-msgstr ""
-
-msgid "calendar (week)"
-msgstr ""
-
-msgid "calendar (year)"
-msgstr ""
-
 #, python-format
 msgid "can't change the %s attribute"
 msgstr ""
@@ -1200,12 +1153,6 @@
 msgid "components_rqlinput_description"
 msgstr "the rql box in the page's header"
 
-msgid "components_rss_feed_url"
-msgstr ""
-
-msgid "components_rss_feed_url_description"
-msgstr ""
-
 msgid "composite"
 msgstr ""
 
@@ -1236,12 +1183,6 @@
 msgid "constraints applying on this relation"
 msgstr ""
 
-msgid "content"
-msgstr ""
-
-msgid "content_format"
-msgstr "content format"
-
 msgid "contentnavigation"
 msgstr "contextual components"
 
@@ -1351,28 +1292,31 @@
 msgid "creating Bookmark (Bookmark bookmarked_by CWUser %(linkto)s)"
 msgstr "creating bookmark for %(linkto)s"
 
-msgid "creating CWConstraint (CWAttribute %(linkto)s constrained_by CWConstraint)"
-msgstr "creating constraint for attribute %(linkto)s"
-
-msgid "creating CWConstraint (CWRelation %(linkto)s constrained_by CWConstraint)"
-msgstr "creating constraint for relation %(linkto)s"
-
 msgid "creating CWAttribute (CWAttribute relation_type CWRType %(linkto)s)"
 msgstr "creating attribute %(linkto)s"
 
+msgid ""
+"creating CWConstraint (CWAttribute %(linkto)s constrained_by CWConstraint)"
+msgstr "creating constraint for attribute %(linkto)s"
+
+msgid ""
+"creating CWConstraint (CWRelation %(linkto)s constrained_by CWConstraint)"
+msgstr "creating constraint for relation %(linkto)s"
+
+msgid "creating CWProperty (CWProperty for_user CWUser %(linkto)s)"
+msgstr "creating property for user %(linkto)s"
+
 msgid "creating CWRelation (CWRelation relation_type CWRType %(linkto)s)"
 msgstr "creating relation %(linkto)s"
 
-msgid "creating CWProperty (CWProperty for_user CWUser %(linkto)s)"
-msgstr "creating property for user %(linkto)s"
-
 msgid "creating CWUser (CWUser in_group CWGroup %(linkto)s)"
 msgstr "creating a new user in group %(linkto)s"
 
 msgid "creating EmailAddress (CWUser %(linkto)s use_email EmailAddress)"
 msgstr "creating email address for user %(linkto)s"
 
-msgid "creating RQLExpression (CWEType %(linkto)s add_permission RQLExpression)"
+msgid ""
+"creating RQLExpression (CWEType %(linkto)s add_permission RQLExpression)"
 msgstr "creating rql expression for add permission on %(linkto)s"
 
 msgid ""
@@ -1387,7 +1331,8 @@
 "creating RQLExpression (CWEType %(linkto)s update_permission RQLExpression)"
 msgstr "creating rql expression for update permission on %(linkto)s"
 
-msgid "creating RQLExpression (CWRType %(linkto)s add_permission RQLExpression)"
+msgid ""
+"creating RQLExpression (CWRType %(linkto)s add_permission RQLExpression)"
 msgstr "creating rql expression for add permission on relations %(linkto)s"
 
 msgid ""
@@ -1556,6 +1501,9 @@
 msgid "destination_state_object"
 msgstr "destination of"
 
+msgid "detach attached file"
+msgstr ""
+
 #, python-format
 msgid "detach attached file %s"
 msgstr ""
@@ -1634,9 +1582,18 @@
 msgid "entities deleted"
 msgstr ""
 
+msgid "entity copied"
+msgstr ""
+
+msgid "entity created"
+msgstr ""
+
 msgid "entity deleted"
 msgstr ""
 
+msgid "entity edited"
+msgstr ""
+
 msgid "entity type"
 msgstr ""
 
@@ -1743,6 +1700,10 @@
 msgid "from"
 msgstr ""
 
+#, python-format
+msgid "from %(date)s"
+msgstr ""
+
 msgid "from_entity"
 msgstr "from entity"
 
@@ -1855,9 +1816,6 @@
 msgid "i18n_login_popup"
 msgstr "login"
 
-msgid "i18n_register_user"
-msgstr "register"
-
 msgid "i18nprevnext_next"
 msgstr "next"
 
@@ -1948,9 +1906,6 @@
 msgid "inlined"
 msgstr ""
 
-msgid "inlined view"
-msgstr ""
-
 msgid "internationalizable"
 msgstr ""
 
@@ -2048,11 +2003,6 @@
 msgid "link a transition to one or more entity type"
 msgstr ""
 
-msgid ""
-"link a transition to one or more rql expression allowing to go through this "
-"transition"
-msgstr ""
-
 msgid "link to each item in"
 msgstr ""
 
@@ -2068,7 +2018,7 @@
 msgid "login"
 msgstr ""
 
-msgid "login or email" 
+msgid "login or email"
 msgstr ""
 
 msgid "login_action"
@@ -2296,9 +2246,6 @@
 msgid "pkey"
 msgstr "key"
 
-msgid "planned_delivery"
-msgstr "planned delivery"
-
 msgid "please correct errors below"
 msgstr ""
 
@@ -2363,8 +2310,8 @@
 msgid "remove this Bookmark"
 msgstr "remove this bookmark"
 
-msgid "remove this Card"
-msgstr "remove this card"
+msgid "remove this CWAttribute"
+msgstr "remove this attribute"
 
 msgid "remove this CWCache"
 msgstr ""
@@ -2378,15 +2325,9 @@
 msgid "remove this CWEType"
 msgstr "remove this entity type"
 
-msgid "remove this CWAttribute"
-msgstr "remove this attribute"
-
 msgid "remove this CWGroup"
 msgstr "remove this group"
 
-msgid "remove this CWRelation"
-msgstr "remove this relation"
-
 msgid "remove this CWPermission"
 msgstr "remove this permission"
 
@@ -2396,6 +2337,9 @@
 msgid "remove this CWRType"
 msgstr "remove this relation type"
 
+msgid "remove this CWRelation"
+msgstr "remove this relation"
+
 msgid "remove this CWUser"
 msgstr "remove this user"
 
@@ -2493,6 +2437,9 @@
 msgid "select a"
 msgstr ""
 
+msgid "select a key first"
+msgstr ""
+
 msgid "select a relation"
 msgstr ""
 
@@ -2612,9 +2559,6 @@
 msgid "symetric"
 msgstr ""
 
-msgid "synopsis"
-msgstr ""
-
 msgid "system entities"
 msgstr ""
 
@@ -2676,6 +2620,10 @@
 msgid "to"
 msgstr ""
 
+#, python-format
+msgid "to %(date)s"
+msgstr ""
+
 msgid "to associate with"
 msgstr ""
 
@@ -2694,6 +2642,9 @@
 msgid "todo_by"
 msgstr "to do by"
 
+msgid "toggle check boxes"
+msgstr ""
+
 msgid "transition is not allowed"
 msgstr ""
 
@@ -2856,9 +2807,6 @@
 "which is the preferred form."
 msgstr ""
 
-msgid "wikiid"
-msgstr "wiki identifier"
-
 #, python-format
 msgid "workflow for %s"
 msgstr ""
@@ -2877,3 +2825,39 @@
 
 msgid "you have been logged out"
 msgstr ""
+
+msgid "you should probably delete that property"
+msgstr ""
+
+#~ msgid "Card"
+#~ msgstr "Card"
+
+#~ msgid "Card_plural"
+#~ msgstr "Cards"
+
+#~ msgid "New Card"
+#~ msgstr "New card"
+
+#~ msgid "This Card"
+#~ msgstr "This card"
+
+#~ msgid "add a Card"
+#~ msgstr "add a card"
+
+#~ msgid "content_format"
+#~ msgstr "content format"
+
+#~ msgid "i18n_register_user"
+#~ msgstr "register"
+
+#~ msgid "planned_delivery"
+#~ msgstr "planned delivery"
+
+#~ msgid "remove this Card"
+#~ msgstr "remove this card"
+
+#~ msgid "trcomment"
+#~ msgstr "comment"
+
+#~ msgid "wikiid"
+#~ msgstr "wiki identifier"
--- a/i18n/es.po	Tue Apr 28 13:28:37 2009 +0200
+++ b/i18n/es.po	Tue Apr 28 19:12:52 2009 +0200
@@ -201,11 +201,71 @@
 msgid "Bytes_plural"
 msgstr "Datos binarios"
 
-msgid "Card"
-msgstr "Ficha"
-
-msgid "Card_plural"
-msgstr "Fichas"
+msgid "CWAttribute"
+msgstr "Atributo"
+
+msgid "CWAttribute_plural"
+msgstr "Atributos"
+
+msgid "CWCache"
+msgstr "Memoria Cache"
+
+msgid "CWCache_plural"
+msgstr "Memorias Caches"
+
+msgid "CWConstraint"
+msgstr "Condición"
+
+msgid "CWConstraintType"
+msgstr "Tipo de condición"
+
+msgid "CWConstraintType_plural"
+msgstr "Tipos de condición"
+
+msgid "CWConstraint_plural"
+msgstr "Condiciones"
+
+msgid "CWEType"
+msgstr "Tipo de entidades"
+
+msgid "CWEType_plural"
+msgstr "Tipos de entidades"
+
+msgid "CWGroup"
+msgstr "Groupo"
+
+msgid "CWGroup_plural"
+msgstr "Groupos"
+
+msgid "CWPermission"
+msgstr "Autorización"
+
+msgid "CWPermission_plural"
+msgstr "Autorizaciones"
+
+msgid "CWProperty"
+msgstr "Propiedad"
+
+msgid "CWProperty_plural"
+msgstr "Propiedades"
+
+msgid "CWRType"
+msgstr "Tipo de relación"
+
+msgid "CWRType_plural"
+msgstr "Tipos de relación"
+
+msgid "CWRelation"
+msgstr "Relación"
+
+msgid "CWRelation_plural"
+msgstr "Relaciones"
+
+msgid "CWUser"
+msgstr "Usuario"
+
+msgid "CWUser_plural"
+msgstr "Usuarios"
 
 msgid "Date"
 msgstr "Fecha"
@@ -232,75 +292,6 @@
 msgid "Do you want to delete the following element(s) ?"
 msgstr "Desea suprimir el(los) elemento(s) siguiente(s)"
 
-msgid "CWCache"
-msgstr "Memoria Cache"
-
-msgid "CWCache_plural"
-msgstr "Memorias Caches"
-
-msgid "CWConstraint"
-msgstr "Condición"
-
-msgid "CWConstraintType"
-msgstr "Tipo de condición"
-
-msgid "CWConstraintType_plural"
-msgstr "Tipos de condición"
-
-msgid "CWConstraint_plural"
-msgstr "Condiciones"
-
-msgid "CWEType"
-msgstr "Tipo de entidades"
-
-msgid "CWEType_plural"
-msgstr "Tipos de entidades"
-
-msgid "CWAttribute"
-msgstr "Atributo"
-
-msgid "CWAttribute_plural"
-msgstr "Atributos"
-
-msgid "CWGroup"
-msgstr "Groupo"
-
-msgid "CWGroup_plural"
-msgstr "Groupos"
-
-msgid "CWRelation"
-msgstr "Relación"
-
-msgid "CWRelation_plural"
-msgstr "Relaciones"
-
-msgid "CWPermission"
-msgstr "Autorización"
-
-msgid "CWPermission_plural"
-msgstr "Autorizaciones"
-
-msgid "CWProperty"
-msgstr "Propiedad"
-
-msgid "CWProperty_plural"
-msgstr "Propiedades"
-
-msgid "CWRType"
-msgstr "Tipo de relación"
-
-msgid "CWRType_plural"
-msgstr "Tipos de relación"
-
-msgid "CWUser"
-msgstr "Usuario"
-
-msgid "CWUser_plural"
-msgstr "Usuarios"
-
-msgid "Email body: "
-msgstr "Contenido del correo electrónico : "
-
 msgid "EmailAddress"
 msgstr "Correo Electrónico"
 
@@ -319,8 +310,8 @@
 msgid "Float_plural"
 msgstr "Números flotantes"
 
-msgid "From: "
-msgstr "De : "
+msgid "From:"
+msgstr ""
 
 msgid "Int"
 msgstr "Número entero"
@@ -337,8 +328,8 @@
 msgid "New Bookmark"
 msgstr "Nuevo Atajo"
 
-msgid "New Card"
-msgstr "Nueva ficha"
+msgid "New CWAttribute"
+msgstr "Nueva definición de relación final"
 
 msgid "New CWCache"
 msgstr "Nueva memoria cache"
@@ -352,15 +343,9 @@
 msgid "New CWEType"
 msgstr "Nuevo tipo de entidad"
 
-msgid "New CWAttribute"
-msgstr "Nueva definición de relación final"
-
 msgid "New CWGroup"
 msgstr "Nuevo grupo"
 
-msgid "New CWRelation"
-msgstr "Nueva definición de relación final"
-
 msgid "New CWPermission"
 msgstr "Nueva autorización"
 
@@ -370,6 +355,9 @@
 msgid "New CWRType"
 msgstr "Nuevo tipo de relación"
 
+msgid "New CWRelation"
+msgstr "Nueva definición de relación final"
+
 msgid "New CWUser"
 msgstr "Nuevo usuario"
 
@@ -406,17 +394,14 @@
 msgid "Please note that this is only a shallow copy"
 msgstr "Recuerde que no es más que una copia superficial"
 
-msgid "Problem occured"
-msgstr "Ha ocurrido un error"
-
 msgid "RQLExpression"
 msgstr "Expresión RQL"
 
 msgid "RQLExpression_plural"
 msgstr "Expresiones RQL"
 
-msgid "Recipients: "
-msgstr "Destinatarios : "
+msgid "Recipients:"
+msgstr ""
 
 msgid "Relations"
 msgstr "Relaciones"
@@ -449,8 +434,8 @@
 msgid "String_plural"
 msgstr "Cadenas de caractéres"
 
-msgid "Subject: "
-msgstr "Objeto : "
+msgid "Subject:"
+msgstr ""
 
 msgid "Submit bug report"
 msgstr "Enviar un reporte de error (bug)"
@@ -476,8 +461,8 @@
 msgid "This Bookmark"
 msgstr "Este atajo"
 
-msgid "This Card"
-msgstr "Esta Ficha"
+msgid "This CWAttribute"
+msgstr "Esta definición de relación final"
 
 msgid "This CWCache"
 msgstr "Esta Memoria Cache"
@@ -491,15 +476,9 @@
 msgid "This CWEType"
 msgstr "Este tipo de Entidad"
 
-msgid "This CWAttribute"
-msgstr "Esta definición de relación final"
-
 msgid "This CWGroup"
 msgstr "Este grupo"
 
-msgid "This CWRelation"
-msgstr "Esta definición de relación no final"
-
 msgid "This CWPermission"
 msgstr "Esta autorización"
 
@@ -509,6 +488,9 @@
 msgid "This CWRType"
 msgstr "Este tipo de relación"
 
+msgid "This CWRelation"
+msgstr "Esta definición de relación no final"
+
 msgid "This CWUser"
 msgstr "Este usuario"
 
@@ -615,13 +597,6 @@
 "representan respectivamente la entidad en transición y el usuarioactual. "
 
 msgid ""
-"a card is a textual content used as documentation, reference, procedure "
-"reminder"
-msgstr ""
-"una ficha es un texto utilizado como documentación, referencia, memoria de "
-"procedimiento..."
-
-msgid ""
 "a simple cache entity characterized by a name and a validity date. The "
 "target application is responsible for updating timestamp when necessary to "
 "invalidate the cache (typically in hooks). Also, checkout the AppRsetObject."
@@ -703,6 +678,12 @@
 msgid "actions_manage_description"
 msgstr ""
 
+msgid "actions_managepermission"
+msgstr ""
+
+msgid "actions_managepermission_description"
+msgstr ""
+
 msgid "actions_muledit"
 msgstr "Edición múltiple"
 
@@ -775,6 +756,12 @@
 msgid "add Bookmark bookmarked_by CWUser object"
 msgstr ""
 
+msgid "add CWAttribute constrained_by CWConstraint subject"
+msgstr "condición"
+
+msgid "add CWAttribute relation_type CWRType object"
+msgstr "definición de atributo"
+
 msgid "add CWEType add_permission RQLExpression subject"
 msgstr "Definir una expresión RQL de agregación"
 
@@ -787,18 +774,6 @@
 msgid "add CWEType update_permission RQLExpression subject"
 msgstr "Definir una expresión RQL de actualización"
 
-msgid "add CWAttribute constrained_by CWConstraint subject"
-msgstr "condición"
-
-msgid "add CWAttribute relation_type CWRType object"
-msgstr "definición de atributo"
-
-msgid "add CWRelation constrained_by CWConstraint subject"
-msgstr "condición"
-
-msgid "add CWRelation relation_type CWRType object"
-msgstr "definición de relación"
-
 msgid "add CWProperty for_user CWUser object"
 msgstr "propiedad"
 
@@ -811,6 +786,12 @@
 msgid "add CWRType read_permission RQLExpression subject"
 msgstr "expresión RQL de lectura"
 
+msgid "add CWRelation constrained_by CWConstraint subject"
+msgstr "condición"
+
+msgid "add CWRelation relation_type CWRType object"
+msgstr "definición de relación"
+
 msgid "add CWUser in_group CWGroup object"
 msgstr "usuario"
 
@@ -841,8 +822,8 @@
 msgid "add a Bookmark"
 msgstr "agregar un atajo"
 
-msgid "add a Card"
-msgstr "agregar una ficha"
+msgid "add a CWAttribute"
+msgstr "agregar un tipo de relación"
 
 msgid "add a CWCache"
 msgstr "agregar una memoria cache"
@@ -856,15 +837,9 @@
 msgid "add a CWEType"
 msgstr "agregar un tipo de entidad"
 
-msgid "add a CWAttribute"
-msgstr "agregar un tipo de relación"
-
 msgid "add a CWGroup"
 msgstr "agregar un grupo de usuarios"
 
-msgid "add a CWRelation"
-msgstr "agregar una relación"
-
 msgid "add a CWPermission"
 msgstr "agregar una autorización"
 
@@ -874,6 +849,9 @@
 msgid "add a CWRType"
 msgstr "agregar un tipo de relación"
 
+msgid "add a CWRelation"
+msgstr "agregar una relación"
+
 msgid "add a CWUser"
 msgstr "agregar un usuario"
 
@@ -939,21 +917,6 @@
 msgid "allowed_transition_object"
 msgstr "Estados de entrada"
 
-msgid "am/pm calendar (month)"
-msgstr "calendario am/pm (mes)"
-
-msgid "am/pm calendar (semester)"
-msgstr "calendario am/pm (semestre)"
-
-msgid "am/pm calendar (week)"
-msgstr "calendario am/pm (semana)"
-
-msgid "am/pm calendar (year)"
-msgstr "calendario am/pm (año)"
-
-msgid "an abstract for this card"
-msgstr "un resumen para esta ficha"
-
 msgid "an electronic mail address associated to a short alias"
 msgstr "una dirección electrónica asociada a este alias"
 
@@ -1106,18 +1069,6 @@
 msgid "calendar"
 msgstr "mostrar un calendario"
 
-msgid "calendar (month)"
-msgstr "calendario (mensual)"
-
-msgid "calendar (semester)"
-msgstr "calendario (semestral)"
-
-msgid "calendar (week)"
-msgstr "calendario (semanal)"
-
-msgid "calendar (year)"
-msgstr "calendario (anual)"
-
 #, python-format
 msgid "can't change the %s attribute"
 msgstr "no puede modificar el atributo %s"
@@ -1232,12 +1183,6 @@
 msgid "components_rqlinput_description"
 msgstr "la barre de demanda rql, en el encabezado de página"
 
-msgid "components_rss_feed_url"
-msgstr ""
-
-msgid "components_rss_feed_url_description"
-msgstr ""
-
 msgid "composite"
 msgstr "composite"
 
@@ -1268,12 +1213,6 @@
 msgid "constraints applying on this relation"
 msgstr "condiciones que se aplican a esta relación"
 
-msgid "content"
-msgstr "contenido"
-
-msgid "content_format"
-msgstr "formato"
-
 msgid "contentnavigation"
 msgstr "composantes contextuales"
 
@@ -1399,28 +1338,31 @@
 msgid "creating Bookmark (Bookmark bookmarked_by CWUser %(linkto)s)"
 msgstr ""
 
-msgid "creating CWConstraint (CWAttribute %(linkto)s constrained_by CWConstraint)"
-msgstr "creación condicionada por el atributo %(linkto)s"
-
-msgid "creating CWConstraint (CWRelation %(linkto)s constrained_by CWConstraint)"
-msgstr "creación condicionada por la relación %(linkto)s"
-
 msgid "creating CWAttribute (CWAttribute relation_type CWRType %(linkto)s)"
 msgstr "creación atributo %(linkto)s"
 
+msgid ""
+"creating CWConstraint (CWAttribute %(linkto)s constrained_by CWConstraint)"
+msgstr "creación condicionada por el atributo %(linkto)s"
+
+msgid ""
+"creating CWConstraint (CWRelation %(linkto)s constrained_by CWConstraint)"
+msgstr "creación condicionada por la relación %(linkto)s"
+
+msgid "creating CWProperty (CWProperty for_user CWUser %(linkto)s)"
+msgstr "creación de una propiedad por el usuario %(linkto)s"
+
 msgid "creating CWRelation (CWRelation relation_type CWRType %(linkto)s)"
 msgstr "creación relación %(linkto)s"
 
-msgid "creating CWProperty (CWProperty for_user CWUser %(linkto)s)"
-msgstr "creación de una propiedad por el usuario %(linkto)s"
-
 msgid "creating CWUser (CWUser in_group CWGroup %(linkto)s)"
 msgstr "creación de un usuario para agregar al grupo %(linkto)s"
 
 msgid "creating EmailAddress (CWUser %(linkto)s use_email EmailAddress)"
 msgstr "creación de una dirección electrónica para el usuario %(linkto)s"
 
-msgid "creating RQLExpression (CWEType %(linkto)s add_permission RQLExpression)"
+msgid ""
+"creating RQLExpression (CWEType %(linkto)s add_permission RQLExpression)"
 msgstr ""
 "creación de una expresión RQL para la autorización de agregar %(linkto)s"
 
@@ -1438,7 +1380,8 @@
 msgstr ""
 "creación de una expresión RQL para la autorización de actualizar %(linkto)s"
 
-msgid "creating RQLExpression (CWRType %(linkto)s add_permission RQLExpression)"
+msgid ""
+"creating RQLExpression (CWRType %(linkto)s add_permission RQLExpression)"
 msgstr ""
 "creación de una expresión RQL para la autorización de agregar relaciones %"
 "(linkto)s"
@@ -1626,6 +1569,9 @@
 msgid "destination_state_object"
 msgstr "destino de"
 
+msgid "detach attached file"
+msgstr "soltar el archivo existente"
+
 #, python-format
 msgid "detach attached file %s"
 msgstr ""
@@ -1706,9 +1652,18 @@
 msgid "entities deleted"
 msgstr "entidades eliminadas"
 
+msgid "entity copied"
+msgstr ""
+
+msgid "entity created"
+msgstr ""
+
 msgid "entity deleted"
 msgstr "entidad eliminada"
 
+msgid "entity edited"
+msgstr ""
+
 msgid "entity type"
 msgstr "tipo de entidad"
 
@@ -1820,6 +1775,10 @@
 msgid "from"
 msgstr "de"
 
+#, python-format
+msgid "from %(date)s"
+msgstr ""
+
 msgid "from_entity"
 msgstr "de la entidad"
 
@@ -1938,9 +1897,6 @@
 msgid "i18n_login_popup"
 msgstr "identificarse"
 
-msgid "i18n_register_user"
-msgstr "registrarse"
-
 msgid "i18nprevnext_next"
 msgstr "siguiente"
 
@@ -2034,9 +1990,6 @@
 msgid "inlined"
 msgstr "puesto en línea"
 
-msgid "inlined view"
-msgstr "vista incluída (en línea)"
-
 msgid "internationalizable"
 msgstr "internacionalizable"
 
@@ -2141,11 +2094,6 @@
 msgid "link a transition to one or more entity type"
 msgstr "lie une transition ‡ un ou plusieurs types d'entitÈs"
 
-msgid ""
-"link a transition to one or more rql expression allowing to go through this "
-"transition"
-msgstr ""
-
 msgid "link to each item in"
 msgstr "lier vers chaque ÈlÈment dans"
 
@@ -2161,6 +2109,9 @@
 msgid "login"
 msgstr "identifiant"
 
+msgid "login or email"
+msgstr ""
+
 msgid "login_action"
 msgstr "identifiez vous"
 
@@ -2389,9 +2340,6 @@
 msgid "pkey"
 msgstr "clÈ"
 
-msgid "planned_delivery"
-msgstr ""
-
 msgid "please correct errors below"
 msgstr "veuillez corriger les erreurs ci-dessous"
 
@@ -2456,8 +2404,8 @@
 msgid "remove this Bookmark"
 msgstr "supprimer ce signet"
 
-msgid "remove this Card"
-msgstr "supprimer cette fiche"
+msgid "remove this CWAttribute"
+msgstr "supprimer cet attribut"
 
 msgid "remove this CWCache"
 msgstr "supprimer ce cache applicatif"
@@ -2471,15 +2419,9 @@
 msgid "remove this CWEType"
 msgstr "supprimer ce type d'entitÈ"
 
-msgid "remove this CWAttribute"
-msgstr "supprimer cet attribut"
-
 msgid "remove this CWGroup"
 msgstr "supprimer ce groupe"
 
-msgid "remove this CWRelation"
-msgstr "supprimer cette relation"
-
 msgid "remove this CWPermission"
 msgstr "supprimer cette permission"
 
@@ -2489,6 +2431,9 @@
 msgid "remove this CWRType"
 msgstr "supprimer cette dÈfinition de relation"
 
+msgid "remove this CWRelation"
+msgstr "supprimer cette relation"
+
 msgid "remove this CWUser"
 msgstr "supprimer cet utilisateur"
 
@@ -2595,6 +2540,9 @@
 msgid "select a"
 msgstr "sÈlectionner un"
 
+msgid "select a key first"
+msgstr ""
+
 msgid "select a relation"
 msgstr "sÈlectionner une relation"
 
@@ -2717,9 +2665,6 @@
 msgid "symetric"
 msgstr "symÈtrique"
 
-msgid "synopsis"
-msgstr "synopsis"
-
 msgid "system entities"
 msgstr "entitÈs systËmes"
 
@@ -2782,6 +2727,10 @@
 msgid "to"
 msgstr "‡"
 
+#, python-format
+msgid "to %(date)s"
+msgstr ""
+
 msgid "to associate with"
 msgstr "pour associer ‡"
 
@@ -2800,6 +2749,9 @@
 msgid "todo_by"
 msgstr "‡ faire par"
 
+msgid "toggle check boxes"
+msgstr ""
+
 msgid "transition is not allowed"
 msgstr "transition non permise"
 
@@ -2973,9 +2925,6 @@
 "org et python-projects@lists.logilab.org), mettez cette propriÈtÈ ‡ vrai sur "
 "l'une d'entre-elle qui sera la forme canonique"
 
-msgid "wikiid"
-msgstr "identifiant wiki"
-
 #, python-format
 msgid "workflow for %s"
 msgstr "workflow pour %s"
@@ -2995,6 +2944,9 @@
 msgid "you have been logged out"
 msgstr "vous avez ÈtÈ dÈconnectÈ"
 
+msgid "you should probably delete that property"
+msgstr ""
+
 #~ msgid "%s constraint failed"
 #~ msgstr "La contrainte %s n'est pas satisfaite"
 
@@ -3004,21 +2956,91 @@
 #~ msgid "%s, or without time: %s"
 #~ msgstr "%s, ou bien sans prÈciser d'heure: %s"
 
+#~ msgid "Card"
+#~ msgstr "Ficha"
+
+#~ msgid "Card_plural"
+#~ msgstr "Fichas"
+
+#~ msgid "Email body: "
+#~ msgstr "Contenido del correo electrónico : "
+
+#~ msgid "From: "
+#~ msgstr "De : "
+
 #~ msgid "Loading"
 #~ msgstr "chargement"
 
+#~ msgid "New Card"
+#~ msgstr "Nueva ficha"
+
+#~ msgid "Problem occured"
+#~ msgstr "Ha ocurrido un error"
+
 #~ msgid "Problem occured while setting new value"
 #~ msgstr "Un problËme est survenu lors de la mise ‡ jour"
 
+#~ msgid "Recipients: "
+#~ msgstr "Destinatarios : "
+
+#~ msgid "Subject: "
+#~ msgstr "Objeto : "
+
+#~ msgid "This Card"
+#~ msgstr "Esta Ficha"
+
+#~ msgid ""
+#~ "a card is a textual content used as documentation, reference, procedure "
+#~ "reminder"
+#~ msgstr ""
+#~ "una ficha es un texto utilizado como documentación, referencia, memoria "
+#~ "de procedimiento..."
+
+#~ msgid "add a Card"
+#~ msgstr "agregar una ficha"
+
+#~ msgid "am/pm calendar (month)"
+#~ msgstr "calendario am/pm (mes)"
+
+#~ msgid "am/pm calendar (semester)"
+#~ msgstr "calendario am/pm (semestre)"
+
+#~ msgid "am/pm calendar (week)"
+#~ msgstr "calendario am/pm (semana)"
+
+#~ msgid "am/pm calendar (year)"
+#~ msgstr "calendario am/pm (año)"
+
+#~ msgid "an abstract for this card"
+#~ msgstr "un resumen para esta ficha"
+
 #~ msgid "and"
 #~ msgstr "et"
 
 #~ msgid "at least one relation %s is required on %s(%s)"
 #~ msgstr "au moins une relation %s est nÈcessaire sur %s(%s)"
 
+#~ msgid "calendar (month)"
+#~ msgstr "calendario (mensual)"
+
+#~ msgid "calendar (semester)"
+#~ msgstr "calendario (semestral)"
+
+#~ msgid "calendar (week)"
+#~ msgstr "calendario (semanal)"
+
+#~ msgid "calendar (year)"
+#~ msgstr "calendario (anual)"
+
 #~ msgid "cancel edition"
 #~ msgstr "annuler l'Èdition"
 
+#~ msgid "content"
+#~ msgstr "contenido"
+
+#~ msgid "content_format"
+#~ msgstr "formato"
+
 #~ msgid ""
 #~ "default language (look at the i18n directory of the application to see "
 #~ "available languages)"
@@ -3026,9 +3048,6 @@
 #~ "langue par dÈfaut (regarder le rÈpertoire i18n de l'application pour voir "
 #~ "les langues disponibles)"
 
-#~ msgid "detach attached file"
-#~ msgstr "soltar el archivo existente"
-
 #~ msgid "filter"
 #~ msgstr "filtrer"
 
@@ -3038,12 +3057,18 @@
 #~ msgid "header"
 #~ msgstr "en-tÃte de page"
 
+#~ msgid "i18n_register_user"
+#~ msgstr "registrarse"
+
 #~ msgid "iCal"
 #~ msgstr "iCal"
 
 #~ msgid "incorrect value for type \"%s\""
 #~ msgstr "valeur incorrecte pour le type \"%s\""
 
+#~ msgid "inlined view"
+#~ msgstr "vista incluída (en línea)"
+
 #~ msgid "linked"
 #~ msgstr "liÈ"
 
@@ -3058,11 +3083,20 @@
 #~ msgid "owned by"
 #~ msgstr "appartient ‡"
 
+#~ msgid "remove this Card"
+#~ msgstr "supprimer cette fiche"
+
 #~ msgid "see also"
 #~ msgstr "voir aussi"
 
 #~ msgid "status will change from %s to %s"
 #~ msgstr "l'Ètat va passer de %s ‡ %s"
 
+#~ msgid "synopsis"
+#~ msgstr "synopsis"
+
+#~ msgid "wikiid"
+#~ msgstr "identifiant wiki"
+
 #~ msgid "workflow history"
 #~ msgstr "historique du workflow"
--- a/i18n/fr.po	Tue Apr 28 13:28:37 2009 +0200
+++ b/i18n/fr.po	Tue Apr 28 19:12:52 2009 +0200
@@ -201,11 +201,71 @@
 msgid "Bytes_plural"
 msgstr "Données binaires"
 
-msgid "Card"
-msgstr "Fiche"
-
-msgid "Card_plural"
-msgstr "Fiches"
+msgid "CWAttribute"
+msgstr "Attribut"
+
+msgid "CWAttribute_plural"
+msgstr "Attributs"
+
+msgid "CWCache"
+msgstr "Cache applicatif"
+
+msgid "CWCache_plural"
+msgstr "Caches applicatifs"
+
+msgid "CWConstraint"
+msgstr "Contrainte"
+
+msgid "CWConstraintType"
+msgstr "Type de contrainte"
+
+msgid "CWConstraintType_plural"
+msgstr "Types de contrainte"
+
+msgid "CWConstraint_plural"
+msgstr "Contraintes"
+
+msgid "CWEType"
+msgstr "Type d'entité"
+
+msgid "CWEType_plural"
+msgstr "Types d'entité"
+
+msgid "CWGroup"
+msgstr "Groupe"
+
+msgid "CWGroup_plural"
+msgstr "Groupes"
+
+msgid "CWPermission"
+msgstr "Permission"
+
+msgid "CWPermission_plural"
+msgstr "Permissions"
+
+msgid "CWProperty"
+msgstr "Propriété"
+
+msgid "CWProperty_plural"
+msgstr "Propriétés"
+
+msgid "CWRType"
+msgstr "Type de relation"
+
+msgid "CWRType_plural"
+msgstr "Types de relation"
+
+msgid "CWRelation"
+msgstr "Relation"
+
+msgid "CWRelation_plural"
+msgstr "Relations"
+
+msgid "CWUser"
+msgstr "Utilisateur"
+
+msgid "CWUser_plural"
+msgstr "Utilisateurs"
 
 msgid "Date"
 msgstr "Date"
@@ -232,75 +292,6 @@
 msgid "Do you want to delete the following element(s) ?"
 msgstr "Voulez vous supprimer le(s) élément(s) suivant(s)"
 
-msgid "CWCache"
-msgstr "Cache applicatif"
-
-msgid "CWCache_plural"
-msgstr "Caches applicatifs"
-
-msgid "CWConstraint"
-msgstr "Contrainte"
-
-msgid "CWConstraintType"
-msgstr "Type de contrainte"
-
-msgid "CWConstraintType_plural"
-msgstr "Types de contrainte"
-
-msgid "CWConstraint_plural"
-msgstr "Contraintes"
-
-msgid "CWEType"
-msgstr "Type d'entité"
-
-msgid "CWEType_plural"
-msgstr "Types d'entité"
-
-msgid "CWAttribute"
-msgstr "Attribut"
-
-msgid "CWAttribute_plural"
-msgstr "Attributs"
-
-msgid "CWGroup"
-msgstr "Groupe"
-
-msgid "CWGroup_plural"
-msgstr "Groupes"
-
-msgid "CWRelation"
-msgstr "Relation"
-
-msgid "CWRelation_plural"
-msgstr "Relations"
-
-msgid "CWPermission"
-msgstr "Permission"
-
-msgid "CWPermission_plural"
-msgstr "Permissions"
-
-msgid "CWProperty"
-msgstr "Propriété"
-
-msgid "CWProperty_plural"
-msgstr "Propriétés"
-
-msgid "CWRType"
-msgstr "Type de relation"
-
-msgid "CWRType_plural"
-msgstr "Types de relation"
-
-msgid "CWUser"
-msgstr "Utilisateur"
-
-msgid "CWUser_plural"
-msgstr "Utilisateurs"
-
-msgid "Email body: "
-msgstr "Contenu du courriel : "
-
 msgid "EmailAddress"
 msgstr "Adresse électronique"
 
@@ -319,8 +310,8 @@
 msgid "Float_plural"
 msgstr "Nombres flottants"
 
-msgid "From: "
-msgstr "De : "
+msgid "From:"
+msgstr ""
 
 msgid "Int"
 msgstr "Nombre entier"
@@ -337,8 +328,8 @@
 msgid "New Bookmark"
 msgstr "Nouveau signet"
 
-msgid "New Card"
-msgstr "Nouvelle fiche"
+msgid "New CWAttribute"
+msgstr "Nouvelle définition de relation"
 
 msgid "New CWCache"
 msgstr "Nouveau cache applicatif"
@@ -352,15 +343,9 @@
 msgid "New CWEType"
 msgstr "Nouveau type d'entité"
 
-msgid "New CWAttribute"
-msgstr "Nouvelle définition de relation finale"
-
 msgid "New CWGroup"
 msgstr "Nouveau groupe"
 
-msgid "New CWRelation"
-msgstr "Nouvelle définition de relation non finale"
-
 msgid "New CWPermission"
 msgstr "Nouvelle permission"
 
@@ -370,6 +355,9 @@
 msgid "New CWRType"
 msgstr "Nouveau type de relation"
 
+msgid "New CWRelation"
+msgstr "Nouvel attribut"
+
 msgid "New CWUser"
 msgstr "Nouvel utilisateur"
 
@@ -406,17 +394,14 @@
 msgid "Please note that this is only a shallow copy"
 msgstr "Attention, cela n'effectue qu'une copie de surface"
 
-msgid "Problem occured"
-msgstr "Une erreur est survenue"
-
 msgid "RQLExpression"
 msgstr "Expression RQL"
 
 msgid "RQLExpression_plural"
 msgstr "Expressions RQL"
 
-msgid "Recipients: "
-msgstr "Destinataires : "
+msgid "Recipients:"
+msgstr "Destinataires :"
 
 msgid "Relations"
 msgstr "Relations"
@@ -449,8 +434,8 @@
 msgid "String_plural"
 msgstr "Chaînes de caractères"
 
-msgid "Subject: "
-msgstr "Sujet : "
+msgid "Subject:"
+msgstr "Sujet :"
 
 msgid "Submit bug report"
 msgstr "Soumettre un rapport de bug"
@@ -476,8 +461,8 @@
 msgid "This Bookmark"
 msgstr "Ce signet"
 
-msgid "This Card"
-msgstr "Cette fiche"
+msgid "This CWAttribute"
+msgstr "Cette définition de relation"
 
 msgid "This CWCache"
 msgstr "Ce cache applicatif"
@@ -491,15 +476,9 @@
 msgid "This CWEType"
 msgstr "Ce type d'entité"
 
-msgid "This CWAttribute"
-msgstr "Cette définition de relation finale"
-
 msgid "This CWGroup"
 msgstr "Ce groupe"
 
-msgid "This CWRelation"
-msgstr "Cette définition de relation non finale"
-
 msgid "This CWPermission"
 msgstr "Cette permission"
 
@@ -509,6 +488,9 @@
 msgid "This CWRType"
 msgstr "Ce type de relation"
 
+msgid "This CWRelation"
+msgstr "Cet attribut"
+
 msgid "This CWUser"
 msgstr "Cet utilisateur"
 
@@ -617,13 +599,6 @@
 "transition et l'utilisateur courant."
 
 msgid ""
-"a card is a textual content used as documentation, reference, procedure "
-"reminder"
-msgstr ""
-"une fiche est un texte utilisé comme documentation, référence, rappel de "
-"procédure..."
-
-msgid ""
 "a simple cache entity characterized by a name and a validity date. The "
 "target application is responsible for updating timestamp when necessary to "
 "invalidate the cache (typically in hooks). Also, checkout the AppRsetObject."
@@ -705,6 +680,12 @@
 msgid "actions_manage_description"
 msgstr ""
 
+msgid "actions_managepermission"
+msgstr ""
+
+msgid "actions_managepermission_description"
+msgstr ""
+
 msgid "actions_muledit"
 msgstr "édition multiple"
 
@@ -777,6 +758,12 @@
 msgid "add Bookmark bookmarked_by CWUser object"
 msgstr "signet"
 
+msgid "add CWAttribute constrained_by CWConstraint subject"
+msgstr "contrainte"
+
+msgid "add CWAttribute relation_type CWRType object"
+msgstr "définition d'attribut"
+
 msgid "add CWEType add_permission RQLExpression subject"
 msgstr "définir une expression RQL d'ajout"
 
@@ -789,18 +776,6 @@
 msgid "add CWEType update_permission RQLExpression subject"
 msgstr "définir une expression RQL de mise à jour"
 
-msgid "add CWAttribute constrained_by CWConstraint subject"
-msgstr "contrainte"
-
-msgid "add CWAttribute relation_type CWRType object"
-msgstr "définition d'attribut"
-
-msgid "add CWRelation constrained_by CWConstraint subject"
-msgstr "contrainte"
-
-msgid "add CWRelation relation_type CWRType object"
-msgstr "définition de relation"
-
 msgid "add CWProperty for_user CWUser object"
 msgstr "propriété"
 
@@ -813,6 +788,12 @@
 msgid "add CWRType read_permission RQLExpression subject"
 msgstr "expression RQL de lecture"
 
+msgid "add CWRelation constrained_by CWConstraint subject"
+msgstr "contrainte"
+
+msgid "add CWRelation relation_type CWRType object"
+msgstr "définition de relation"
+
 msgid "add CWUser in_group CWGroup object"
 msgstr "utilisateur"
 
@@ -843,8 +824,8 @@
 msgid "add a Bookmark"
 msgstr "ajouter un signet"
 
-msgid "add a Card"
-msgstr "ajouter une fiche"
+msgid "add a CWAttribute"
+msgstr "ajouter un attribut"
 
 msgid "add a CWCache"
 msgstr "ajouter un cache applicatif"
@@ -858,15 +839,9 @@
 msgid "add a CWEType"
 msgstr "ajouter un type d'entité"
 
-msgid "add a CWAttribute"
-msgstr "ajouter un type de relation"
-
 msgid "add a CWGroup"
 msgstr "ajouter un groupe d'utilisateurs"
 
-msgid "add a CWRelation"
-msgstr "ajouter une relation"
-
 msgid "add a CWPermission"
 msgstr "ajouter une permission"
 
@@ -876,6 +851,9 @@
 msgid "add a CWRType"
 msgstr "ajouter un type de relation"
 
+msgid "add a CWRelation"
+msgstr "ajouter une relation"
+
 msgid "add a CWUser"
 msgstr "ajouter un utilisateur"
 
@@ -941,21 +919,6 @@
 msgid "allowed_transition_object"
 msgstr "états en entrée"
 
-msgid "am/pm calendar (month)"
-msgstr "calendrier am/pm (mois)"
-
-msgid "am/pm calendar (semester)"
-msgstr "calendrier am/pm (semestre)"
-
-msgid "am/pm calendar (week)"
-msgstr "calendrier am/pm (semaine)"
-
-msgid "am/pm calendar (year)"
-msgstr "calendrier am/pm (année)"
-
-msgid "an abstract for this card"
-msgstr "un résumé pour cette fiche"
-
 msgid "an electronic mail address associated to a short alias"
 msgstr "une addresse électronique associée à un alias"
 
@@ -1107,18 +1070,6 @@
 msgid "calendar"
 msgstr "afficher un calendrier"
 
-msgid "calendar (month)"
-msgstr "calendrier (mensuel)"
-
-msgid "calendar (semester)"
-msgstr "calendrier (semestriel)"
-
-msgid "calendar (week)"
-msgstr "calendrier (hebdo)"
-
-msgid "calendar (year)"
-msgstr "calendrier (annuel)"
-
 #, python-format
 msgid "can't change the %s attribute"
 msgstr "ne peut changer l'attribut %s"
@@ -1233,12 +1184,6 @@
 msgid "components_rqlinput_description"
 msgstr "la barre de requête rql, dans l'en-tête de page"
 
-msgid "components_rss_feed_url"
-msgstr "syndication rss"
-
-msgid "components_rss_feed_url_description"
-msgstr ""
-
 msgid "composite"
 msgstr "composite"
 
@@ -1269,12 +1214,6 @@
 msgid "constraints applying on this relation"
 msgstr "contraintes s'appliquant à cette relation"
 
-msgid "content"
-msgstr "contenu"
-
-msgid "content_format"
-msgstr "format"
-
 msgid "contentnavigation"
 msgstr "composants contextuels"
 
@@ -1401,28 +1340,31 @@
 msgid "creating Bookmark (Bookmark bookmarked_by CWUser %(linkto)s)"
 msgstr "création d'un signet pour %(linkto)s"
 
-msgid "creating CWConstraint (CWAttribute %(linkto)s constrained_by CWConstraint)"
-msgstr "création d'une contrainte pour l'attribut %(linkto)s"
-
-msgid "creating CWConstraint (CWRelation %(linkto)s constrained_by CWConstraint)"
-msgstr "création d'une contrainte pour la relation %(linkto)s"
-
 msgid "creating CWAttribute (CWAttribute relation_type CWRType %(linkto)s)"
 msgstr "création d'un attribut %(linkto)s"
 
+msgid ""
+"creating CWConstraint (CWAttribute %(linkto)s constrained_by CWConstraint)"
+msgstr "création d'une contrainte pour l'attribut %(linkto)s"
+
+msgid ""
+"creating CWConstraint (CWRelation %(linkto)s constrained_by CWConstraint)"
+msgstr "création d'une contrainte pour la relation %(linkto)s"
+
+msgid "creating CWProperty (CWProperty for_user CWUser %(linkto)s)"
+msgstr "création d'une propriété pour l'utilisateur %(linkto)s"
+
 msgid "creating CWRelation (CWRelation relation_type CWRType %(linkto)s)"
 msgstr "création relation %(linkto)s"
 
-msgid "creating CWProperty (CWProperty for_user CWUser %(linkto)s)"
-msgstr "création d'une propriété pour l'utilisateur %(linkto)s"
-
 msgid "creating CWUser (CWUser in_group CWGroup %(linkto)s)"
 msgstr "création d'un utilisateur à rajouter au groupe %(linkto)s"
 
 msgid "creating EmailAddress (CWUser %(linkto)s use_email EmailAddress)"
 msgstr "création d'une adresse électronique pour l'utilisateur %(linkto)s"
 
-msgid "creating RQLExpression (CWEType %(linkto)s add_permission RQLExpression)"
+msgid ""
+"creating RQLExpression (CWEType %(linkto)s add_permission RQLExpression)"
 msgstr "création d'une expression RQL pour la permission d'ajout de %(linkto)s"
 
 msgid ""
@@ -1439,7 +1381,8 @@
 msgstr ""
 "création d'une expression RQL pour la permission de mise à jour de %(linkto)s"
 
-msgid "creating RQLExpression (CWRType %(linkto)s add_permission RQLExpression)"
+msgid ""
+"creating RQLExpression (CWRType %(linkto)s add_permission RQLExpression)"
 msgstr ""
 "création d'une expression RQL pour la permission d'ajout des relations %"
 "(linkto)s"
@@ -1626,6 +1569,9 @@
 msgid "destination_state_object"
 msgstr "destination de"
 
+msgid "detach attached file"
+msgstr "détacher le fichier existant"
+
 #, python-format
 msgid "detach attached file %s"
 msgstr "détacher le fichier existant %s"
@@ -1706,9 +1652,18 @@
 msgid "entities deleted"
 msgstr "entités supprimées"
 
+msgid "entity copied"
+msgstr ""
+
+msgid "entity created"
+msgstr ""
+
 msgid "entity deleted"
 msgstr "entité supprimée"
 
+msgid "entity edited"
+msgstr ""
+
 msgid "entity type"
 msgstr "type d'entité"
 
@@ -1819,6 +1774,10 @@
 msgid "from"
 msgstr "de"
 
+#, python-format
+msgid "from %(date)s"
+msgstr ""
+
 msgid "from_entity"
 msgstr "de l'entité"
 
@@ -1938,9 +1897,6 @@
 msgid "i18n_login_popup"
 msgstr "s'authentifier"
 
-msgid "i18n_register_user"
-msgstr "s'enregister"
-
 msgid "i18nprevnext_next"
 msgstr "suivant"
 
@@ -2034,9 +1990,6 @@
 msgid "inlined"
 msgstr "mise en ligne"
 
-msgid "inlined view"
-msgstr "vue embarquée (en ligne)"
-
 msgid "internationalizable"
 msgstr "internationalisable"
 
@@ -2142,11 +2095,6 @@
 msgid "link a transition to one or more entity type"
 msgstr "lie une transition à un ou plusieurs types d'entités"
 
-msgid ""
-"link a transition to one or more rql expression allowing to go through this "
-"transition"
-msgstr ""
-
 msgid "link to each item in"
 msgstr "lier vers chaque élément dans"
 
@@ -2393,9 +2341,6 @@
 msgid "pkey"
 msgstr "clé"
 
-msgid "planned_delivery"
-msgstr "livraison prévue"
-
 msgid "please correct errors below"
 msgstr "veuillez corriger les erreurs ci-dessous"
 
@@ -2460,8 +2405,8 @@
 msgid "remove this Bookmark"
 msgstr "supprimer ce signet"
 
-msgid "remove this Card"
-msgstr "supprimer cette fiche"
+msgid "remove this CWAttribute"
+msgstr "supprimer cet attribut"
 
 msgid "remove this CWCache"
 msgstr "supprimer ce cache applicatif"
@@ -2475,15 +2420,9 @@
 msgid "remove this CWEType"
 msgstr "supprimer ce type d'entité"
 
-msgid "remove this CWAttribute"
-msgstr "supprimer cet attribut"
-
 msgid "remove this CWGroup"
 msgstr "supprimer ce groupe"
 
-msgid "remove this CWRelation"
-msgstr "supprimer cette relation"
-
 msgid "remove this CWPermission"
 msgstr "supprimer cette permission"
 
@@ -2493,6 +2432,9 @@
 msgid "remove this CWRType"
 msgstr "supprimer cette définition de relation"
 
+msgid "remove this CWRelation"
+msgstr "supprimer cette relation"
+
 msgid "remove this CWUser"
 msgstr "supprimer cet utilisateur"
 
@@ -2599,6 +2541,9 @@
 msgid "select a"
 msgstr "sélectionner un"
 
+msgid "select a key first"
+msgstr ""
+
 msgid "select a relation"
 msgstr "sélectionner une relation"
 
@@ -2721,9 +2666,6 @@
 msgid "symetric"
 msgstr "symétrique"
 
-msgid "synopsis"
-msgstr "synopsis"
-
 msgid "system entities"
 msgstr "entités systèmes"
 
@@ -2786,6 +2728,10 @@
 msgid "to"
 msgstr "à"
 
+#, python-format
+msgid "to %(date)s"
+msgstr ""
+
 msgid "to associate with"
 msgstr "pour associer à"
 
@@ -2804,6 +2750,9 @@
 msgid "todo_by"
 msgstr "à faire par"
 
+msgid "toggle check boxes"
+msgstr ""
+
 msgid "transition is not allowed"
 msgstr "transition non permise"
 
@@ -2977,9 +2926,6 @@
 "org et python-projects@lists.logilab.org), mettez cette propriété à vrai sur "
 "l'une d'entre-elle qui sera la forme canonique"
 
-msgid "wikiid"
-msgstr "identifiant wiki"
-
 #, python-format
 msgid "workflow for %s"
 msgstr "workflow pour %s"
@@ -2999,6 +2945,9 @@
 msgid "you have been logged out"
 msgstr "vous avez été déconnecté"
 
+msgid "you should probably delete that property"
+msgstr ""
+
 #~ msgid "%s constraint failed"
 #~ msgstr "La contrainte %s n'est pas satisfaite"
 
@@ -3008,21 +2957,88 @@
 #~ msgid "%s, or without time: %s"
 #~ msgstr "%s, ou bien sans préciser d'heure: %s"
 
+#~ msgid "Card"
+#~ msgstr "Fiche"
+
+#~ msgid "Card_plural"
+#~ msgstr "Fiches"
+
+#~ msgid "Email body: "
+#~ msgstr "Contenu du courriel : "
+
+#~ msgid "From: "
+#~ msgstr "De : "
+
 #~ msgid "Loading"
 #~ msgstr "chargement"
 
+#~ msgid "New Card"
+#~ msgstr "Nouvelle fiche"
+
+#~ msgid "Problem occured"
+#~ msgstr "Une erreur est survenue"
+
 #~ msgid "Problem occured while setting new value"
 #~ msgstr "Un problème est survenu lors de la mise à jour"
 
+#~ msgid "This Card"
+#~ msgstr "Cette fiche"
+
+#~ msgid ""
+#~ "a card is a textual content used as documentation, reference, procedure "
+#~ "reminder"
+#~ msgstr ""
+#~ "une fiche est un texte utilisé comme documentation, référence, rappel de "
+#~ "procédure..."
+
+#~ msgid "add a Card"
+#~ msgstr "ajouter une fiche"
+
+#~ msgid "am/pm calendar (month)"
+#~ msgstr "calendrier am/pm (mois)"
+
+#~ msgid "am/pm calendar (semester)"
+#~ msgstr "calendrier am/pm (semestre)"
+
+#~ msgid "am/pm calendar (week)"
+#~ msgstr "calendrier am/pm (semaine)"
+
+#~ msgid "am/pm calendar (year)"
+#~ msgstr "calendrier am/pm (année)"
+
+#~ msgid "an abstract for this card"
+#~ msgstr "un résumé pour cette fiche"
+
 #~ msgid "and"
 #~ msgstr "et"
 
 #~ msgid "at least one relation %s is required on %s(%s)"
 #~ msgstr "au moins une relation %s est nécessaire sur %s(%s)"
 
+#~ msgid "calendar (month)"
+#~ msgstr "calendrier (mensuel)"
+
+#~ msgid "calendar (semester)"
+#~ msgstr "calendrier (semestriel)"
+
+#~ msgid "calendar (week)"
+#~ msgstr "calendrier (hebdo)"
+
+#~ msgid "calendar (year)"
+#~ msgstr "calendrier (annuel)"
+
 #~ msgid "cancel edition"
 #~ msgstr "annuler l'édition"
 
+#~ msgid "components_rss_feed_url"
+#~ msgstr "syndication rss"
+
+#~ msgid "content"
+#~ msgstr "contenu"
+
+#~ msgid "content_format"
+#~ msgstr "format"
+
 #~ msgid ""
 #~ "default language (look at the i18n directory of the application to see "
 #~ "available languages)"
@@ -3030,9 +3046,6 @@
 #~ "langue par défaut (regarder le répertoire i18n de l'application pour voir "
 #~ "les langues disponibles)"
 
-#~ msgid "detach attached file"
-#~ msgstr "détacher le fichier existant"
-
 #~ msgid "filter"
 #~ msgstr "filtrer"
 
@@ -3042,12 +3055,18 @@
 #~ msgid "header"
 #~ msgstr "en-tête de page"
 
+#~ msgid "i18n_register_user"
+#~ msgstr "s'enregister"
+
 #~ msgid "iCal"
 #~ msgstr "iCal"
 
 #~ msgid "incorrect value for type \"%s\""
 #~ msgstr "valeur incorrecte pour le type \"%s\""
 
+#~ msgid "inlined view"
+#~ msgstr "vue embarquée (en ligne)"
+
 #~ msgid "linked"
 #~ msgstr "lié"
 
@@ -3062,11 +3081,26 @@
 #~ msgid "owned by"
 #~ msgstr "appartient à"
 
+#~ msgid "planned_delivery"
+#~ msgstr "livraison prévue"
+
+#~ msgid "remove this Card"
+#~ msgstr "supprimer cette fiche"
+
 #~ msgid "see also"
 #~ msgstr "voir aussi"
 
 #~ msgid "status will change from %s to %s"
 #~ msgstr "l'état va passer de %s à %s"
 
+#~ msgid "synopsis"
+#~ msgstr "synopsis"
+
+#~ msgid "trcomment"
+#~ msgstr "commentaire"
+
+#~ msgid "wikiid"
+#~ msgstr "identifiant wiki"
+
 #~ msgid "workflow history"
 #~ msgstr "historique du workflow"
--- a/misc/migration/3.2.0_Any.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/misc/migration/3.2.0_Any.py	Tue Apr 28 19:12:52 2009 +0200
@@ -1,3 +1,4 @@
 rql('SET X value "main-template" WHERE X is CWProperty, '
     'X pkey "ui.main-template", X value "main"')
 checkpoint()
+
--- a/misc/migration/bootstrapmigration_repository.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/misc/migration/bootstrapmigration_repository.py	Tue Apr 28 19:12:52 2009 +0200
@@ -7,6 +7,9 @@
 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
 """
 
+if applcubicwebversion < (3, 2, 0) and cubicwebversion >= (3, 2, 0):
+   add_cube('card', update_database=False)
+
 if applcubicwebversion < (2, 47, 0) and cubicwebversion >= (2, 47, 0):
     from cubicweb.server import schemaserial
     schemaserial.HAS_FULLTEXT_CONTAINER = False
@@ -15,7 +18,7 @@
     schemaserial.HAS_FULLTEXT_CONTAINER = True
 
 
- 
+
 if applcubicwebversion < (2, 50, 0) and cubicwebversion >= (2, 50, 0):
     session.set_shared_data('do-not-insert-is_instance_of', True)
     add_relation_type('is_instance_of')
@@ -40,4 +43,4 @@
     sql('CREATE INDEX deleted_entities_dtime_idx ON deleted_entities(dtime)')
     sql('CREATE INDEX deleted_entities_extid_idx ON deleted_entities(extid)')
     checkpoint()
-   
+
--- a/schema.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/schema.py	Tue Apr 28 19:12:52 2009 +0200
@@ -77,7 +77,7 @@
 ## cubicweb provides a RichString class for convenience
 class RichString(ybo.String):
     """Convenience RichString attribute type
-    The follwing declaration::
+    The following declaration::
 
       class Card(EntityType):
           content = RichString(fulltextindexed=True, default_format='text/rest')
--- a/selectors.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/selectors.py	Tue Apr 28 19:12:52 2009 +0200
@@ -51,7 +51,8 @@
 
 from yams import BASE_TYPES
 
-from cubicweb import Unauthorized, NoSelectableObject, NotAnEntity, role
+from cubicweb import (Unauthorized, NoSelectableObject, NotAnEntity,
+                      role, typed_eid)
 from cubicweb.vregistry import (NoSelectableObject, Selector,
                                 chainall, objectify_selector)
 from cubicweb.cwconfig import CubicWebConfiguration
@@ -404,7 +405,7 @@
 @objectify_selector
 @lltrace
 def authenticated_user(cls, req, *args, **kwargs):
-    """accept if user is anonymous"""
+    """accept if user is authenticated"""
     if req.cnx.anonymous_connection:
         return 0
     return 1
@@ -529,6 +530,20 @@
         return score
 
 
+class match_transition(match_search_state):
+    @lltrace
+    def __call__(self, cls, req, rset=None, row=None, col=0, **kwargs):
+        try:
+            trname = req.execute('Any XN WHERE X is Transition, X eid %(x)s, X name XN',
+                                 {'x': typed_eid(req.form['treid'])})[0][0]
+        except (KeyError, IndexError):
+            return 0
+        # XXX check this is a transition that apply to the object?
+        if not trname in self.expected:
+            return 0
+        return 1
+
+
 class match_view(match_search_state):
     """accept if the current view is in one of the expected vid given to the
     initializer
--- a/server/repository.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/server/repository.py	Tue Apr 28 19:12:52 2009 +0200
@@ -60,7 +60,7 @@
         remove inserted eid from repository type/source cache
         """
         self.repo.clear_caches(self.session.query_data('pendingeids', ()))
-        
+
     def rollback_event(self):
         """the observed connections pool has been rollbacked,
         remove inserted eid from repository type/source cache
@@ -84,7 +84,7 @@
         session.repo.system_source.fti_unindex_entity(session, entity.eid)
         for container in entity.fti_containers():
             session.repo.index_entity(session, container)
-            
+
     def commit_event(self):
         pass
 
@@ -120,14 +120,14 @@
             'DELETE X %s Y WHERE NOT X eid %%(x)s, Y eid %%(y)s' % rtype,
             {'x': eidfrom, 'y': eidto}, 'y')
 
-    
+
 class Repository(object):
     """a repository provides access to a set of persistent storages for
     entities and relations
 
     XXX protect pyro access
     """
-    
+
     def __init__(self, config, vreg=None, debug=False):
         self.config = config
         if vreg is None:
@@ -155,7 +155,7 @@
         for uri, source_config in config.sources().items():
             if uri == 'admin':
                 # not an actual source
-                continue 
+                continue
             source = self.get_source(uri, source_config)
             self.sources_by_uri[uri] = source
             self.sources.append(source)
@@ -214,16 +214,16 @@
                 source.init_creating()
         # close initialization pool and reopen fresh ones for proper
         # initialization now that we know cubes
-        self._get_pool().close(True) 
+        self._get_pool().close(True)
         for i in xrange(config['connections-pool-size']):
             self._available_pools.put_nowait(ConnectionsPool(self.sources))
-        
+
     # internals ###############################################################
 
     def get_source(self, uri, source_config):
         source_config['uri'] = uri
         return get_source(source_config, self.schema, self)
-        
+
     def set_schema(self, schema, resetvreg=True):
         schema.rebuild_infered_relations()
         self.info('set schema %s %#x', schema.name, id(schema))
@@ -259,7 +259,7 @@
             except Exception, ex:
                 import traceback
                 traceback.print_exc()
-                raise Exception('Is the database initialised ? (cause: %s)' % 
+                raise Exception('Is the database initialised ? (cause: %s)' %
                                 (ex.args and ex.args[0].strip() or 'unknown')), \
                                 None, sys.exc_info()[-1]
             self.info('set the actual schema')
@@ -277,7 +277,7 @@
             session.close()
         self.config.init_cubes(self.get_cubes())
         self.set_schema(appschema)
-        
+
     def set_bootstrap_schema(self, schema):
         """disable hooks when setting a bootstrap schema, but restore
         the configuration for the next time
@@ -295,7 +295,7 @@
         config.schema_hooks = True
         config.notification_hooks = True
         config.application_hooks = True
-            
+
     def start_looping_tasks(self):
         assert isinstance(self._looping_tasks, list), 'already started'
         for i, (interval, func) in enumerate(self._looping_tasks):
@@ -308,7 +308,7 @@
 
     def looping_task(self, interval, func):
         """register a function to be called every `interval` seconds.
-        
+
         looping tasks can only be registered during repository initialization,
         once done this method will fail.
         """
@@ -321,7 +321,7 @@
         """start function in a separated thread"""
         t = RepoThread(func, self._running_threads)
         t.start()
-        
+
     #@locked
     def _get_pool(self):
         try:
@@ -332,7 +332,7 @@
                             'connections) or to much load on the server (in '
                             'which case you can try to set a bigger '
                             'connections pools size)')
-        
+
     def _free_pool(self, pool):
         pool.rollback()
         self._available_pools.put_nowait(pool)
@@ -382,7 +382,7 @@
                       ((hits + misses) * 100) / (hits + misses + nocache))
         except ZeroDivisionError:
             pass
-        
+
     def authenticate_user(self, session, login, password):
         """validate login / password, raise AuthenticationError on failure
         return associated CWUser instance on success
@@ -415,9 +415,9 @@
         euser.groups
         euser.properties
         return euser
-        
+
     # public (dbapi) interface ################################################
-            
+
     def get_schema(self):
         """return the application schema. This is a public method, not
         requiring a session id
@@ -469,7 +469,7 @@
         finally:
             session.close()
         return vcconf
-    
+
     @cached
     def source_defs(self):
         sources = self.config.sources().copy()
@@ -526,13 +526,13 @@
         finally:
             session.close()
         return True
-        
+
     def connect(self, login, password, cnxprops=None):
         """open a connection for a given user
 
         base_url may be needed to send mails
         cnxtype indicate if this is a pyro connection or a in-memory connection
-        
+
         raise `AuthenticationError` if the authentication failed
         raise `ConnectionError` if we can't open a connection
         """
@@ -584,7 +584,7 @@
                 raise
         finally:
             session.reset_pool()
-    
+
     def describe(self, sessionid, eid):
         """return a tuple (type, source, extid) for the entity with id <eid>"""
         session = self._get_session(sessionid, setpool=True)
@@ -618,12 +618,12 @@
         self.debug('begin commit for session %s', sessionid)
         try:
             self._get_session(sessionid, setpool=True).commit()
-        except (ValidationError, Unauthorized): 
+        except (ValidationError, Unauthorized):
             raise
         except:
             self.exception('unexpected error')
             raise
-        
+
     def rollback(self, sessionid):
         """commit transaction for the session with the given id"""
         self.debug('begin rollback for session %s', sessionid)
@@ -645,7 +645,7 @@
         session.close()
         del self._sessions[sessionid]
         self.info('closed session %s for user %s', sessionid, session.user.login)
-    
+
     def user_info(self, sessionid, props=None):
         """this method should be used by client to:
         * check session id validity
@@ -659,9 +659,9 @@
                 session.change_property(prop, value)
         user = session.user
         return user.eid, user.login, user.groups, user.properties
-            
+
     # public (inter-repository) interface #####################################
-    
+
     def entities_modified_since(self, etypes, mtime):
         """function designed to be called from an external repository which
         is using this one as a rql source for synchronization, and return a
@@ -683,7 +683,7 @@
             session.close()
 
     # session handling ########################################################
-        
+
     def close_sessions(self):
         """close every opened sessions"""
         for sessionid in self._sessions.keys():
@@ -705,7 +705,7 @@
                 self.close(session.id)
                 nbclosed += 1
         return nbclosed
-    
+
     def internal_session(self, cnxprops=None):
         """return a dbapi like connection/cursor using internal user which
         have every rights on the repository. You'll *have to* commit/rollback
@@ -716,7 +716,7 @@
         session = InternalSession(self, cnxprops)
         session.set_pool()
         return session
-            
+
     def _get_session(self, sessionid, setpool=False):
         """return the user associated to the given session identifier"""
         try:
@@ -731,7 +731,7 @@
     # * correspondance between eid and (type, source)
     # * correspondance between eid and local id (i.e. specific to a given source)
     # * searchable text indexes
-    
+
     def type_and_source_from_eid(self, eid, session=None):
         """return a tuple (type, source, extid) for the entity with id <eid>"""
         try:
@@ -771,15 +771,15 @@
             rqlcache.pop('Any X WHERE X eid %s' % eid, None)
             for source in self.sources:
                 source.clear_eid_cache(eid, etype)
-                
+
     def type_from_eid(self, eid, session=None):
         """return the type of the entity with id <eid>"""
         return self.type_and_source_from_eid(eid, session)[0]
-    
+
     def source_from_eid(self, eid, session=None):
         """return the source for the given entity's eid"""
         return self.sources_by_uri[self.type_and_source_from_eid(eid, session)[1]]
-        
+
     def eid2extid(self, source, eid, session=None):
         """get local id from an eid"""
         etype, uri, extid = self.type_and_source_from_eid(eid, session)
@@ -848,7 +848,7 @@
         except:
             session.rollback(reset_pool)
             raise
-        
+
     def add_info(self, session, entity, source, extid=None, complete=True):
         """add type and source info for an eid into the system table,
         and index the entity with the full text index
@@ -862,11 +862,11 @@
         if self.do_fti:
             FTIndexEntityOp(session, entity=entity)
         CleanupEidTypeCacheOp(session)
-        
+
     def delete_info(self, session, eid):
         self._prepare_delete_info(session, eid)
         self._delete_info(session, eid)
-        
+
     def _prepare_delete_info(self, session, eid):
         """prepare the repository for deletion of an entity:
         * update the fti
@@ -877,7 +877,7 @@
         pending = session.query_data('pendingeids', set(), setdefault=True)
         pending.add(eid)
         CleanupEidTypeCacheOp(session)
-        
+
     def _delete_info(self, session, eid):
         """delete system information on deletion of an entity:
         * delete all relations on this entity
@@ -886,7 +886,7 @@
         etype, uri, extid = self.type_and_source_from_eid(eid, session)
         self._clear_eid_relations(session, etype, eid)
         self.system_source.delete_info(session, eid, etype, uri, extid)
-        
+
     def _clear_eid_relations(self, session, etype, eid):
         """when a entity is deleted, build and execute rql query to delete all
         its relations
@@ -917,7 +917,7 @@
             return
         alreadydone.add(entity.eid)
         self.system_source.fti_index_entity(session, entity)
-        
+
     def locate_relation_source(self, session, subject, rtype, object):
         subjsource = self.source_from_eid(subject, session)
         objsource = self.source_from_eid(object, session)
@@ -928,17 +928,17 @@
         else:
             source = subjsource
         return source
-    
+
     def locate_etype_source(self, etype):
         for source in self.sources:
             if source.support_entity(etype, 1):
                 return source
         else:
             raise ETypeNotSupportedBySources(etype)
-        
+
     def glob_add_entity(self, session, entity):
         """add an entity to the repository
-        
+
         the entity eid should originaly be None and a unique eid is assigned to
         the entity instance
         """
@@ -981,7 +981,7 @@
                 self.hm.call_hooks('after_add_relation', attr, session,
                                     entity.eid, attr, value)
         return entity.eid
-        
+
     def glob_update_entity(self, session, entity):
         """replace an entity in the repository
         the type and the eid of an entity must not be changed
@@ -1051,7 +1051,7 @@
         if source.should_call_hooks:
             self.hm.call_hooks('after_delete_entity', etype, session, eid)
         # don't clear cache here this is done in a hook on commit
-        
+
     def glob_add_relation(self, session, subject, rtype, object):
         """add a relation to the repository"""
         assert subject is not None
@@ -1089,7 +1089,7 @@
 
 
     # pyro handling ###########################################################
-    
+
     def pyro_register(self, host=''):
         """register the repository as a pyro object"""
         from Pyro import core
@@ -1108,7 +1108,7 @@
         self.info(msg, nsgroup, nsid)
         self.pyro_registered = True
         return daemon
-    
+
     def pyro_nameserver(self, host=None, group=None):
         """locate and bind the the name server to the daemon"""
         from Pyro import naming, errors
@@ -1123,25 +1123,25 @@
         return nameserver
 
     # multi-sources planner helpers ###########################################
-    
+
     @cached
     def rel_type_sources(self, rtype):
         return [source for source in self.sources
                 if source.support_relation(rtype)
                 or rtype in source.dont_cross_relations]
-    
+
     @cached
     def can_cross_relation(self, rtype):
         return [source for source in self.sources
                 if source.support_relation(rtype)
                 and rtype in source.cross_relations]
-    
+
     @cached
     def is_multi_sources_relation(self, rtype):
         return any(source for source in self.sources
                    if not source is self.system_source
                    and source.support_relation(rtype))
-    
+
 
 def pyro_unregister(config):
     """unregister the repository from the pyro name server"""
--- a/server/sources/extlite.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/server/sources/extlite.py	Tue Apr 28 19:12:52 2009 +0200
@@ -22,7 +22,7 @@
         timeout -= 0.2
         if timeout <= 0:
             raise RuntimeError("svn source is busy, can't acquire connection lock")
-        
+
 class ConnectionWrapper(object):
     def __init__(self, source=None):
         self.source = source
@@ -34,19 +34,19 @@
             timeout_acquire(self.source._cnxlock, 5)
             self._cnx = self.source._sqlcnx
         return self._cnx
-    
+
     def commit(self):
         if self._cnx is not None:
             self._cnx.commit()
-        
+
     def rollback(self):
         if self._cnx is not None:
             self._cnx.rollback()
-        
+
     def cursor(self):
         return self.cnx.cursor()
 
-    
+
 class SQLiteAbstractSource(AbstractSource):
     """an abstract class for external sources using a sqlite database helper
     """
@@ -59,7 +59,7 @@
             native.NONSYSTEM_ETYPES.add(etype)
         for rtype in cls.support_relations:
             native.NONSYSTEM_RELATIONS.add(rtype)
-        
+
     options = (
         ('helper-db-path',
          {'type' : 'string',
@@ -69,10 +69,10 @@
           'inputlevel': 2,
           }),
     )
-            
+
     def __init__(self, repo, appschema, source_config, *args, **kwargs):
         # the helper db is used to easy querying and will store everything but
-        # actual file content 
+        # actual file content
         dbpath = source_config.get('helper-db-path')
         if dbpath is None:
             dbpath = join(repo.config.appdatahome,
@@ -91,7 +91,7 @@
         # * create the connection when needed
         # * use a lock to be sure only one connection is used
         self._cnxlock = threading.Lock()
-        
+
     @property
     def _sqlcnx(self):
         # XXX: sqlite connections can only be used in the same thread, so
@@ -138,13 +138,13 @@
                          self.repo.config['uid'])
             chown(self.dbpath, self.repo.config['uid'])
         restrict_perms_to_user(self.dbpath, self.info)
-        
+
     def set_schema(self, schema):
         super(SQLiteAbstractSource, self).set_schema(schema)
         if self._need_sql_create and self._is_schema_complete() and self.dbpath:
             self._create_database()
         self.rqlsqlgen = self.sqlgen_class(schema, self.sqladapter.dbhelper)
-                
+
     def get_connection(self):
         return ConnectionWrapper(self)
 
@@ -168,11 +168,11 @@
                 cnx._cnx = None
             finally:
                 self._cnxlock.release()
-        
+
     def syntax_tree_search(self, session, union,
                            args=None, cachekey=None, varmap=None, debug=0):
-        """return result from this source for a rql query (actually from a rql 
-        syntax tree and a solution dictionary mapping each used variable to a 
+        """return result from this source for a rql query (actually from a rql
+        syntax tree and a solution dictionary mapping each used variable to a
         possible type). If cachekey is given, the query necessary to fetch the
         results (but not the results themselves) may be cached using this key.
         """
@@ -185,7 +185,7 @@
         args = self.sqladapter.merge_args(args, query_args)
         cursor = session.pool[self.uri]
         cursor.execute(sql, args)
-        return self.sqladapter.process_result(cursor) 
+        return self.sqladapter.process_result(cursor)
 
     def local_add_entity(self, session, entity):
         """insert the entity in the local database.
@@ -198,7 +198,7 @@
         attrs = self.sqladapter.preprocess_entity(entity)
         sql = self.sqladapter.sqlgen.insert(SQL_PREFIX + str(entity.e_schema), attrs)
         cu.execute(sql, attrs)
-        
+
     def add_entity(self, session, entity):
         """add a new entity to the source"""
         raise NotImplementedError()
@@ -213,14 +213,14 @@
         cu = session.pool[self.uri]
         if attrs is None:
             attrs = self.sqladapter.preprocess_entity(entity)
-        sql = self.sqladapter.sqlgen.update(SQL_PREFIX + str(entity.e_schema), attrs,
-                                            [SQL_PREFIX + 'eid'])
+        sql = self.sqladapter.sqlgen.update(SQL_PREFIX + str(entity.e_schema),
+                                            attrs, [SQL_PREFIX + 'eid'])
         cu.execute(sql, attrs)
-        
+
     def update_entity(self, session, entity):
         """update an entity in the source"""
         raise NotImplementedError()
-        
+
     def delete_entity(self, session, etype, eid):
         """delete an entity from the source
 
@@ -228,11 +228,11 @@
         source. Main usage is to delete repository content when a Repository
         entity is deleted.
         """
-        sqlcursor = session.pool[self.uri]        
+        sqlcursor = session.pool[self.uri]
         attrs = {SQL_PREFIX + 'eid': eid}
         sql = self.sqladapter.sqlgen.delete(SQL_PREFIX + etype, attrs)
         sqlcursor.execute(sql, attrs)
-    
+
     def delete_relation(self, session, subject, rtype, object):
         """delete a relation from the source"""
         rschema = self.schema.rschema(rtype)
@@ -246,5 +246,5 @@
         else:
             attrs = {'eid_from': subject, 'eid_to': object}
             sql = self.sqladapter.sqlgen.delete('%s_relation' % rtype, attrs)
-        sqlcursor = session.pool[self.uri]        
+        sqlcursor = session.pool[self.uri]
         sqlcursor.execute(sql, attrs)
--- a/view.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/view.py	Tue Apr 28 19:12:52 2009 +0200
@@ -51,6 +51,7 @@
  cubicweb:variables         CDATA   #IMPLIED
  cubicweb:displayactions    CDATA   #IMPLIED
  cubicweb:fallbackvid       CDATA   #IMPLIED
+ cubicweb:fname             CDATA   #IMPLIED
  cubicweb:vid               CDATA   #IMPLIED
  cubicweb:rql               CDATA   #IMPLIED
  cubicweb:actualrql         CDATA   #IMPLIED
@@ -479,10 +480,7 @@
     """base class for components"""
     __registry__ = 'components'
     __select__ = yes()
-    property_defs = {
-        _('visible'):  dict(type='Boolean', default=True,
-                            help=_('display the component or not')),
-        }
+    property_defs = {}
 
     def div_class(self):
         return '%s %s' % (self.propval('htmlclass'), self.id)
--- a/web/box.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/web/box.py	Tue Apr 28 19:12:52 2009 +0200
@@ -24,13 +24,13 @@
 
 class BoxTemplate(View):
     """base template for boxes, usually a (contextual) list of possible
-    
+
     actions. Various classes attributes may be used to control the box
     rendering.
-    
+
     You may override on of the formatting callbacks is this is not necessary
     for your custom box.
-    
+
     Classes inheriting from this class usually only have to override call
     to fetch desired actions, and then to do something like  ::
 
@@ -39,7 +39,7 @@
     __registry__ = 'boxes'
     __select__ = match_context_prop()
     registered = classmethod(require_group_compat(View.registered))
-    
+
     categories_in_order = ()
     property_defs = {
         _('visible'): dict(type='Boolean', default=True,
@@ -76,9 +76,9 @@
         if escape:
             title = html_escape(title)
         return self.box_action(self._action(title, path, **kwargs))
-    
+
     def _action(self, title, path, **kwargs):
-        return UnregisteredAction(self.req, self.rset, title, path, **kwargs)        
+        return UnregisteredAction(self.req, self.rset, title, path, **kwargs)
 
     # formating callbacks
 
@@ -91,12 +91,12 @@
         cls = getattr(action, 'html_class', lambda: None)() or self.htmlitemclass
         return BoxLink(action.url(), self.req._(action.title),
                        cls, self.boxitem_link_tooltip(action))
-        
+
 
 class RQLBoxTemplate(BoxTemplate):
     """abstract box for boxes displaying the content of a rql query not
     related to the current result set.
-    
+
     It rely on etype, rtype (both optional, usable to control registration
     according to application schema and display according to connected
     user's rights) and rql attributes
@@ -104,11 +104,11 @@
 #XXX    __selectors__ = BoxTemplate.__selectors__ + (etype_rtype_selector,)
 
     rql  = None
-    
+
     def to_display_rql(self):
         assert self.rql is not None, self.id
         return (self.rql,)
-    
+
     def call(self, **kwargs):
         try:
             rset = self.req.execute(*self.to_display_rql())
@@ -123,7 +123,7 @@
             box.append(self.mk_action(tname, entity.absolute_url()))
         box.render(w=self.w)
 
-        
+
 class UserRQLBoxTemplate(RQLBoxTemplate):
     """same as rql box template but the rql is build using the eid of the
     request's user
@@ -132,14 +132,14 @@
     def to_display_rql(self):
         assert self.rql is not None, self.id
         return (self.rql, {'x': self.req.user.eid}, 'x')
-    
+
 
 class EntityBoxTemplate(BoxTemplate):
     """base class for boxes related to a single entity"""
     __select__ = BoxTemplate.__select__ & one_line_rset() & primary_view()
     registered = accepts_compat(has_relation_compat(condition_compat(BoxTemplate.registered)))
     context = 'incontext'
-    
+
     def call(self, row=0, col=0, **kwargs):
         """classes inheriting from EntityBoxTemplate should define cell_call"""
         self.cell_call(row, col, **kwargs)
@@ -165,7 +165,7 @@
     subclasses should define at least id, rtype and target
     class attributes.
     """
-    
+
     def cell_call(self, row, col, view=None):
         self.req.add_js('cubicweb.ajax.js')
         entity = self.entity(row, col)
@@ -178,7 +178,7 @@
 
     def div_id(self):
         return self.id
-        
+
     def box_item(self, entity, etarget, rql, label):
         """builds HTML link to edit relation between `entity` and `etarget`
         """
@@ -189,7 +189,7 @@
         label = u'[<a href="%s">%s</a>] %s' % (url, label,
                                                etarget.view('incontext'))
         return RawBoxItem(label, liclass=u'invisible')
-    
+
     def w_related(self, box, entity):
         """appends existing relations to the `box`"""
         rql = 'DELETE S %s O WHERE S eid %%(s)s, O eid %%(o)s' % self.rtype
@@ -197,7 +197,7 @@
         for etarget in related:
             box.append(self.box_item(entity, etarget, rql, u'-'))
         return len(related)
-    
+
     def w_unrelated(self, box, entity):
         """appends unrelated entities to the `box`"""
         rql = 'SET S %s O WHERE S eid %%(s)s, O eid %%(o)s' % self.rtype
@@ -220,7 +220,7 @@
                 rset = self.req.eid_rset(eid)
                 entities.append(rset.get_entity(0, 0))
         return entities
-        
+
     def related_entities(self, entity):
         return entity.related(self.rtype, get_role(self), entities=True)
 
--- a/web/component.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/web/component.py	Tue Apr 28 19:12:52 2009 +0200
@@ -62,6 +62,11 @@
     id = 'navigation'
     __select__ = paginated_rset()
 
+    property_defs = {
+        _('visible'):  dict(type='Boolean', default=True,
+                            help=_('display the component or not')),
+        }
+
     page_size_property = 'navigation.page-size'
     start_param = '__start'
     stop_param = '__stop'
--- a/web/data/cubicweb.ajax.js	Tue Apr 28 13:28:37 2009 +0200
+++ b/web/data/cubicweb.ajax.js	Tue Apr 28 19:12:52 2009 +0200
@@ -9,17 +9,37 @@
 
 var JSON_BASE_URL = baseuri() + 'json?';
 
+function _loadAjaxHtmlHead(node, head, tag, srcattr) {
+    var loaded = [];
+    jQuery('head ' + tag).each(function(i) {
+	loaded.push(this.getAttribute(srcattr));
+    });
+    node.find(tag).each(function(i) {
+	if (!loaded.contains(this.getAttribute(srcattr))) {
+	    jQuery(this).appendTo(head);
+	}
+    });
+    node.find(tag).remove();
+}
+
 /*
  * inspect dom response, search for a <div class="ajaxHtmlHead"> node and
  * put its content into the real document's head.
  * This enables dynamic css and js loading and is used by replacePageChunk
  */
 function loadAjaxHtmlHead(node) {
-    jQuery(node).find('div.ajaxHtmlHead').appendTo(jQuery('head'));
+    var head = jQuery('head');
+    var node = jQuery(node).find('div.ajaxHtmlHead');
+    _loadAjaxHtmlHead(node, head, 'script', 'src');
+    _loadAjaxHtmlHead(node, head, 'link', 'href');
+    node.find('*').appendTo(head);
+}
+
+function preprocessAjaxLoad(node, newdomnode) {
+    loadAjaxHtmlHead(newdomnode);
 }
 
 function postAjaxLoad(node) {
-    loadAjaxHtmlHead(node);
     // find sortable tables if there are some
     if (typeof(Sortable) != 'undefined') {
 	Sortable.sortTables(node);
@@ -37,6 +57,7 @@
     if (typeof roundedCornersOnLoad != 'undefined') {
 	roundedCornersOnLoad();
     }
+    loadDynamicFragments(node);
     jQuery(CubicWeb).trigger('ajax-loaded');
 }
 
@@ -60,6 +81,7 @@
     }
     ajax(url, data, function(response) {
 	var domnode = getDomFromResponse(response);
+	preprocessAjaxLoad(node, domnode);
 	if (mode == 'swap') {
 	    var origId = node.id;
 	    node = swapDOM(node, domnode);
@@ -83,8 +105,12 @@
 /* finds each dynamic fragment in the page and executes the
  * the associated RQL to build them (Async call)
  */
-function loadDynamicFragments() {
-    var fragments = jQuery('div.dynamicFragment');
+function loadDynamicFragments(node) {
+    if (node) {
+	var fragments = jQuery(node).find('div.dynamicFragment');
+    } else {
+	var fragments = jQuery('div.dynamicFragment');
+    }
     if (fragments.length == 0) {
 	return;
     }
@@ -106,7 +132,7 @@
     }
 }
 
-jQuery(document).ready(loadDynamicFragments);
+jQuery(document).ready(function() {loadDynamicFragments();});
 
 //============= base AJAX functions to make remote calls =====================//
 
@@ -282,6 +308,7 @@
     var props = {};
     if (node) {
 	props['rql'] = rql;
+	props['fname'] = 'view';
 	props['pageid'] = pageid;
 	if (vid) { props['vid'] = vid; }
 	if (extraparams) { jQuery.extend(props, extraparams); }
--- a/web/form.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/web/form.py	Tue Apr 28 19:12:52 2009 +0200
@@ -30,28 +30,6 @@
     http_cache_manager = NoHTTPCacheManager
     add_to_breadcrumbs = False
 
-    def __init__(self, req, rset, **kwargs):
-        super(FormViewMixIn, self).__init__(req, rset, **kwargs)
-        # get validation session data which may have been previously set.
-        # deleting validation errors here breaks form reloading (errors are
-        # no more available), they have to be deleted by application's publish
-        # method on successful commit
-        formurl = req.url()
-        forminfo = req.get_session_data(formurl)
-        if forminfo:
-            req.data['formvalues'] = forminfo['values']
-            req.data['formerrors'] = errex = forminfo['errors']
-            req.data['displayederrors'] = set()
-            # if some validation error occured on entity creation, we have to
-            # get the original variable name from its attributed eid
-            foreid = errex.entity
-            for var, eid in forminfo['eidmap'].items():
-                if foreid == eid:
-                    errex.eid = var
-                    break
-            else:
-                errex.eid = foreid
-
     def html_headers(self):
         """return a list of html headers (eg something to be inserted between
         <head> and </head> of the returned page
@@ -80,22 +58,13 @@
             self.req.set_page_data('rql_varmaker', varmaker)
         self.varmaker = varmaker
 
-    # XXX deprecated with new form system. Should disappear
-
-    domid = 'entityForm'
-    category = 'form'
-    controller = 'edit'
-    http_cache_manager = NoHTTPCacheManager
-    add_to_breadcrumbs = False
-
     def __init__(self, req, rset, **kwargs):
         super(FormMixIn, self).__init__(req, rset, **kwargs)
         # get validation session data which may have been previously set.
         # deleting validation errors here breaks form reloading (errors are
         # no more available), they have to be deleted by application's publish
         # method on successful commit
-        formurl = req.url()
-        forminfo = req.get_session_data(formurl)
+        forminfo = req.get_session_data(req.url())
         if forminfo:
             req.data['formvalues'] = forminfo['values']
             req.data['formerrors'] = errex = forminfo['errors']
@@ -110,6 +79,14 @@
             else:
                 errex.eid = foreid
 
+    # XXX deprecated with new form system. Should disappear
+
+    domid = 'entityForm'
+    category = 'form'
+    controller = 'edit'
+    http_cache_manager = NoHTTPCacheManager
+    add_to_breadcrumbs = False
+
     def html_headers(self):
         """return a list of html headers (eg something to be inserted between
         <head> and </head> of the returned page
@@ -371,10 +348,11 @@
         values found in 1. and 2. are expected te be already some 'display'
         value while those found in 3. and 4. are expected to be correctly typed.
         """
-        if field.name in self._previous_values:
-            value = self._previous_values[field.name]
-        elif field.name in self.req.form:
-            value = self.req.form[field.name]
+        qname = self.form_field_name(field)
+        if qname in self._previous_values:
+            value = self._previous_values[qname]
+        elif qname in self.req.form:
+            value = self.req.form[qname]
         else:
             if field.name in rendervalues:
                 value = rendervalues[field.name]
@@ -449,6 +427,9 @@
                 self.form_add_hidden('__linkto', linkto)
                 msg = '%s %s' % (msg, self.req._('and linked'))
             self.form_add_hidden('__message', msg)
+        # in case of direct instanciation
+        self.schema = self.edited_entity.schema
+        self.vreg = self.edited_entity.vreg
 
     def _errex_match_field(self, errex, field):
         """return true if the field has some error in given validation exception
--- a/web/formfields.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/web/formfields.py	Tue Apr 28 19:12:52 2009 +0200
@@ -220,9 +220,10 @@
             else:
                 # else we want a format selector
                 # XXX compute vocabulary
-                widget = Select
+                widget = Select()
                 fcstr = FormatConstraint()
                 choices = [(req._(fmt), fmt) for fmt in fcstr.vocabulary(req=req)]
+                widget.attrs['size'] = 1
             field = StringField(name=self.name + '_format', widget=widget,
                                 choices=choices)
             req.data[self] = field
@@ -412,11 +413,13 @@
         return value
 
 
-def stringfield_from_constraints(constraints, **kwargs):
+def stringfield_from_constraints(constraints, card, **kwargs):
     field = None
     for cstr in constraints:
         if isinstance(cstr, StaticVocabularyConstraint):
             kwargs.setdefault('widget', Select())
+            if card in '?1':
+                kwargs['widget'].attrs.setdefault('size', 1)
             return StringField(choices=cstr.vocabulary, **kwargs)
         if isinstance(cstr, SizeConstraint) and cstr.max is not None:
             if cstr.max > 257:
@@ -478,7 +481,7 @@
                 return RichTextField(**kwargs)
             # return StringField or TextField according to constraints
             constraints = rschema.rproperty(eschema, targetschema, 'constraints')
-            return stringfield_from_constraints(constraints, **kwargs)
+            return stringfield_from_constraints(constraints, card, **kwargs)
         if fieldclass is FileField:
             for metadata in ('format', 'encoding'):
                 metaschema = eschema.has_metadata(rschema, metadata)
--- a/web/uicfg.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/web/uicfg.py	Tue Apr 28 19:12:52 2009 +0200
@@ -11,7 +11,7 @@
 __docformat__ = "restructuredtext en"
 from cubicweb.rtags import RelationTags
 
-# editforms.AutomaticEntityForm configuration #################################
+# autoform.AutomaticEntityForm configuration ##################################
 
 # relations'category (eg primary/secondary/generic/metadata/generated)
 rcategories = RelationTags()
--- a/web/views/actions.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/actions.py	Tue Apr 28 19:12:52 2009 +0200
@@ -15,7 +15,7 @@
     )
 from cubicweb.web.action import Action
 from cubicweb.web.views import linksearch_select_url, vid_from_rset
-from cubicweb.web.views.editforms import AutomaticEntityForm
+from cubicweb.web.views.autoform import AutomaticEntityForm
 
 _ = unicode
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/views/autoform.py	Tue Apr 28 19:12:52 2009 +0200
@@ -0,0 +1,328 @@
+"""The automatic entity form.
+
+:organization: Logilab
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+"""
+__docformat__ = "restructuredtext en"
+
+from logilab.common.decorators import iclassmethod
+
+from cubicweb import typed_eid
+from cubicweb.web import stdmsgs, uicfg
+from cubicweb.web.form import FieldNotFound, EntityFieldsForm
+from cubicweb.web.formfields import guess_field
+from cubicweb.web.formwidgets import Button, SubmitButton
+_ = unicode
+
+class AutomaticEntityForm(EntityFieldsForm):
+    """base automatic form to edit any entity.
+
+    Designed to be flly generated from schema but highly configurable through:
+    * rtags (rcategories, rfields, rwidgets, inlined, rpermissions)
+    * various standard form parameters
+
+    You can also easily customise it by adding/removing fields in
+    AutomaticEntityForm instances.
+    """
+    id = 'edition'
+
+    cwtarget = 'eformframe'
+    cssclass = 'entityForm'
+    copy_nav_params = True
+    form_buttons = [SubmitButton(stdmsgs.BUTTON_OK),
+                    Button(stdmsgs.BUTTON_APPLY, cwaction='apply'),
+                    Button(stdmsgs.BUTTON_CANCEL, cwaction='cancel')]
+    attrcategories = ('primary', 'secondary')
+    # class attributes below are actually stored in the uicfg module since we
+    # don't want them to be reloaded
+    rcategories = uicfg.rcategories
+    rfields = uicfg.rfields
+    rwidgets = uicfg.rwidgets
+    rinlined = uicfg.rinlined
+    rpermissions_overrides = uicfg.rpermissions_overrides
+
+    @classmethod
+    def vreg_initialization_completed(cls):
+        """set default category tags for relations where it's not yet defined in
+        the category relation tags
+        """
+        for eschema in cls.schema.entities():
+            for rschema, tschemas, role in eschema.relation_definitions(True):
+                for tschema in tschemas:
+                    if role == 'subject':
+                        X, Y = eschema, tschema
+                        card = rschema.rproperty(X, Y, 'cardinality')[0]
+                        composed = rschema.rproperty(X, Y, 'composite') == 'object'
+                    else:
+                        X, Y = tschema, eschema
+                        card = rschema.rproperty(X, Y, 'cardinality')[1]
+                        composed = rschema.rproperty(X, Y, 'composite') == 'subject'
+                    if not cls.rcategories.rtag(rschema, role, X, Y):
+                        if card in '1+':
+                            if not rschema.is_final() and composed:
+                                category = 'generated'
+                            else:
+                                category = 'primary'
+                        elif rschema.is_final():
+                            category = 'secondary'
+                        else:
+                            category = 'generic'
+                        cls.rcategories.set_rtag(category, rschema, role, X, Y)
+
+    @classmethod
+    def erelations_by_category(cls, entity, categories=None, permission=None, rtags=None):
+        """return a list of (relation schema, target schemas, role) matching
+        categories and permission
+        """
+        if categories is not None:
+            if not isinstance(categories, (list, tuple, set, frozenset)):
+                categories = (categories,)
+            if not isinstance(categories, (set, frozenset)):
+                categories = frozenset(categories)
+        eschema  = entity.e_schema
+        if rtags is None:
+            rtags = cls.rcategories
+        permsoverrides = cls.rpermissions_overrides
+        if entity.has_eid():
+            eid = entity.eid
+        else:
+            eid = None
+        for rschema, targetschemas, role in eschema.relation_definitions(True):
+            # check category first, potentially lower cost than checking
+            # permission which may imply rql queries
+            if categories is not None:
+                targetschemas = [tschema for tschema in targetschemas
+                                 if rtags.etype_rtag(eschema, rschema, role, tschema) in categories]
+                if not targetschemas:
+                    continue
+            if permission is not None:
+                # tag allowing to hijack the permission machinery when
+                # permission is not verifiable until the entity is actually
+                # created...
+                if eid is None and '%s_on_new' % permission in permsoverrides.etype_rtags(eschema, rschema, role):
+                    yield (rschema, targetschemas, role)
+                    continue
+                if rschema.is_final():
+                    if not rschema.has_perm(entity.req, permission, eid):
+                        continue
+                elif role == 'subject':
+                    if not ((eid is None and rschema.has_local_role(permission)) or
+                            rschema.has_perm(entity.req, permission, fromeid=eid)):
+                        continue
+                    # on relation with cardinality 1 or ?, we need delete perm as well
+                    # if the relation is already set
+                    if (permission == 'add'
+                        and rschema.cardinality(eschema, targetschemas[0], role) in '1?'
+                        and eid and entity.related(rschema.type, role)
+                        and not rschema.has_perm(entity.req, 'delete', fromeid=eid,
+                                                 toeid=entity.related(rschema.type, role)[0][0])):
+                        continue
+                elif role == 'object':
+                    if not ((eid is None and rschema.has_local_role(permission)) or
+                            rschema.has_perm(entity.req, permission, toeid=eid)):
+                        continue
+                    # on relation with cardinality 1 or ?, we need delete perm as well
+                    # if the relation is already set
+                    if (permission == 'add'
+                        and rschema.cardinality(targetschemas[0], eschema, role) in '1?'
+                        and eid and entity.related(rschema.type, role)
+                        and not rschema.has_perm(entity.req, 'delete', toeid=eid,
+                                                 fromeid=entity.related(rschema.type, role)[0][0])):
+                        continue
+            yield (rschema, targetschemas, role)
+
+    @classmethod
+    def esrelations_by_category(cls, entity, categories=None, permission=None):
+        """filter out result of relations_by_category(categories, permission) by
+        removing final relations
+
+        return a sorted list of (relation's label, relation'schema, role)
+        """
+        result = []
+        for rschema, ttypes, role in cls.erelations_by_category(
+            entity, categories, permission):
+            if rschema.is_final():
+                continue
+            result.append((rschema.display_name(entity.req, role), rschema, role))
+        return sorted(result)
+
+    @iclassmethod
+    def field_by_name(cls_or_self, name, role='subject', eschema=None):
+        """return field with the given name and role. If field is not explicitly
+        defined for the form but `eclass` is specified, guess_field will be
+        called.
+        """
+        try:
+            return super(AutomaticEntityForm, cls_or_self).field_by_name(name, role)
+        except FieldNotFound: # XXX should raise more explicit exception
+            if eschema is None or not name in cls_or_self.schema:
+                raise
+            rschema = cls_or_self.schema.rschema(name)
+            fieldcls = cls_or_self.rfields.etype_rtag(eschema, rschema, role)
+            if fieldcls:
+                return fieldcls(name=name, role=role, eidparam=True)
+            widget = cls_or_self.rwidgets.etype_rtag(eschema, rschema, role)
+            if widget:
+                field = guess_field(eschema, rschema, role,
+                                    eidparam=True, widget=widget)
+            else:
+                field = guess_field(eschema, rschema, role, eidparam=True)
+            if field is None:
+                raise
+            return field
+
+    def __init__(self, *args, **kwargs):
+        super(AutomaticEntityForm, self).__init__(*args, **kwargs)
+        entity = self.edited_entity
+        if entity.has_eid():
+            entity.complete()
+        for rschema, role in self.editable_attributes():
+            try:
+                self.field_by_name(rschema.type, role)
+                continue # explicitly specified
+            except FieldNotFound:
+                # has to be guessed
+                try:
+                    field = self.field_by_name(rschema.type, role,
+                                               eschema=entity.e_schema)
+                    self.fields.append(field)
+                except FieldNotFound:
+                    # meta attribute such as <attr>_format
+                    continue
+        self.maxrelitems = self.req.property_value('navigation.related-limit')
+        self.force_display = bool(self.req.form.get('__force_display'))
+
+    @property
+    def related_limit(self):
+        if self.force_display:
+            return None
+        return self.maxrelitems + 1
+
+    def relations_by_category(self, categories=None, permission=None):
+        """return a list of (relation schema, target schemas, role) matching
+        given category(ies) and permission
+        """
+        return self.erelations_by_category(self.edited_entity, categories,
+                                           permission)
+
+    def inlined_relations(self):
+        """return a list of (relation schema, target schemas, role) matching
+        given category(ies) and permission
+        """
+        # we'll need an initialized varmaker if there are some inlined relation
+        self.initialize_varmaker()
+        return self.erelations_by_category(self.edited_entity, True, 'add', self.rinlined)
+
+    def srelations_by_category(self, categories=None, permission=None):
+        """filter out result of relations_by_category(categories, permission) by
+        removing final relations
+
+        return a sorted list of (relation's label, relation'schema, role)
+        """
+        return self.esrelations_by_category(self.edited_entity, categories,
+                                           permission)
+
+    def action(self):
+        """return the form's action attribute. Default to validateform if not
+        explicitly overriden.
+        """
+        try:
+            return self._action
+        except AttributeError:
+            return self.build_url('validateform')
+
+    def set_action(self, value):
+        """override default action"""
+        self._action = value
+
+    action = property(action, set_action)
+
+    def editable_attributes(self):
+        """return a list of (relation schema, role) to edit for the entity"""
+        return [(rschema, x) for rschema, _, x in self.relations_by_category(
+            self.attrcategories, 'add') if rschema != 'eid']
+
+    def relations_table(self):
+        """yiels 3-tuples (rtype, target, related_list)
+        where <related_list> itself a list of :
+          - node_id (will be the entity element's DOM id)
+          - appropriate javascript's togglePendingDelete() function call
+          - status 'pendingdelete' or ''
+          - oneline view of related entity
+        """
+        entity = self.edited_entity
+        pending_deletes = self.req.get_pending_deletes(entity.eid)
+        for label, rschema, role in self.srelations_by_category('generic', 'add'):
+            relatedrset = entity.related(rschema, role, limit=self.related_limit)
+            if rschema.has_perm(self.req, 'delete'):
+                toggable_rel_link_func = toggable_relation_link
+            else:
+                toggable_rel_link_func = lambda x, y, z: u''
+            related = []
+            for row in xrange(relatedrset.rowcount):
+                nodeid = relation_id(entity.eid, rschema, role,
+                                     relatedrset[row][0])
+                if nodeid in pending_deletes:
+                    status = u'pendingDelete'
+                    label = '+'
+                else:
+                    status = u''
+                    label = 'x'
+                dellink = toggable_rel_link_func(entity.eid, nodeid, label)
+                eview = self.view('oneline', relatedrset, row=row)
+                related.append((nodeid, dellink, status, eview))
+            yield (rschema, role, related)
+
+    def restore_pending_inserts(self, cell=False):
+        """used to restore edition page as it was before clicking on
+        'search for <some entity type>'
+        """
+        eid = self.edited_entity.eid
+        cell = cell and "div_insert_" or "tr"
+        pending_inserts = set(self.req.get_pending_inserts(eid))
+        for pendingid in pending_inserts:
+            eidfrom, rtype, eidto = pendingid.split(':')
+            if typed_eid(eidfrom) == eid: # subject
+                label = display_name(self.req, rtype, 'subject')
+                reid = eidto
+            else:
+                label = display_name(self.req, rtype, 'object')
+                reid = eidfrom
+            jscall = "javascript: cancelPendingInsert('%s', '%s', null, %s);" \
+                     % (pendingid, cell, eid)
+            rset = self.req.eid_rset(reid)
+            eview = self.view('text', rset, row=0)
+            # XXX find a clean way to handle baskets
+            if rset.description[0][0] == 'Basket':
+                eview = '%s (%s)' % (eview, display_name(self.req, 'Basket'))
+            yield rtype, pendingid, jscall, label, reid, eview
+
+    # should_* method extracted to allow overriding
+
+    def should_inline_relation_form(self, rschema, targettype, role):
+        """return true if the given relation with entity has role and a
+        targettype target should be inlined
+        """
+        return self.rinlined.etype_rtag(self.edited_entity.id, rschema, role, targettype)
+
+    def should_display_inline_creation_form(self, rschema, existant, card):
+        """return true if a creation form should be inlined
+
+        by default true if there is no related entity and we need at least one
+        """
+        return not existant and card in '1+'
+
+    def should_display_add_new_relation_link(self, rschema, existant, card):
+        """return true if we should add a link to add a new creation form
+        (through ajax call)
+
+        by default true if there is no related entity or if the relation has
+        multiple cardinality
+        """
+        return not existant or card in '+*'
+
+
+def etype_relation_field(etype, rtype, role='subject'):
+    eschema = AutomaticEntityForm.schema.eschema(etype)
+    return AutomaticEntityForm.field_by_name(rtype, role, eschema)
--- a/web/views/basecomponents.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/basecomponents.py	Tue Apr 28 19:12:52 2009 +0200
@@ -20,12 +20,16 @@
 
 _ = unicode
 
+VISIBLE_PROP_DEF = {
+    _('visible'):  dict(type='Boolean', default=False,
+                        help=_('display the component or not')),
+    }
 
 class RQLInputForm(Component):
     """build the rql input form, usually displayed in the header"""
     id = 'rqlinput'
-    visible = False
-       
+    property_defs = VISIBLE_PROP_DEF
+
     def call(self, view=None):
         if hasattr(view, 'filter_box_context_info'):
             rset = view.filter_box_context_info()[0]
@@ -53,7 +57,10 @@
 class ApplLogo(Component):
     """build the application logo, usually displayed in the header"""
     id = 'logo'
-    site_wide = True # don't want user to hide this component using an eproperty
+    property_defs = VISIBLE_PROP_DEF
+    # don't want user to hide this component using an cwproperty
+    site_wide = True
+
     def call(self):
         self.w(u'<a href="%s"><img class="logo" src="%s" alt="logo"/></a>'
                % (self.req.base_url(), self.req.external_resource('LOGO')))
@@ -62,6 +69,7 @@
 class ApplHelp(Component):
     """build the help button, usually displayed in the header"""
     id = 'help'
+    property_defs = VISIBLE_PROP_DEF
     def call(self):
         self.w(u'<a href="%s" class="help" title="%s">&nbsp;</a>'
                % (self.build_url(_restpath='doc/main'),
@@ -72,8 +80,10 @@
     """if the user is the anonymous user, build a link to login
     else a link to the connected user object with a loggout link
     """
+    property_defs = VISIBLE_PROP_DEF
+    # don't want user to hide this component using an cwproperty
+    site_wide = True
     id = 'loggeduserlink'
-    site_wide = True # don't want user to hide this component using an eproperty
 
     def call(self):
         if not self.req.cnx.anonymous_connection:
@@ -93,7 +103,7 @@
             box.render(w=self.w)
         else:
             self.anon_user_link()
-            
+
     def anon_user_link(self):
         if self.config['auth-mode'] == 'cookie':
             self.w(self.req._('anonymous'))
@@ -116,7 +126,9 @@
     """
     __select__ = yes()
     id = 'applmessages'
-    site_wide = True # don't want user to hide this component using an eproperty
+    property_defs = VISIBLE_PROP_DEF
+    # don't want user to hide this component using an cwproperty
+    site_wide = True
 
     def call(self):
         msgs = [msg for msg in (self.req.get_shared_data('sources_error', pop=True),
@@ -132,11 +144,12 @@
 class ApplicationName(Component):
     """display the application name"""
     id = 'appliname'
+    property_defs = VISIBLE_PROP_DEF
 
     def call(self):
         self.w(u'<span id="appliName"><a href="%s">%s</a></span>' % (self.req.base_url(),
                                                          self.req.property_value('ui.site-title')))
-        
+
 
 class SeeAlsoVComponent(RelatedObjectsVComponent):
     """display any entity's see also"""
@@ -149,7 +162,7 @@
     title = _('contentnavigation_seealso')
     help = _('contentnavigation_seealso_description')
 
-    
+
 class EtypeRestrictionComponent(Component):
     """displays the list of entity types contained in the resultset
     to be able to filter accordingly.
@@ -157,8 +170,11 @@
     id = 'etypenavigation'
     __select__ = two_etypes_rset() | match_form_params('__restrtype', '__restrtypes',
                                                        '__restrrql')
+    property_defs = VISIBLE_PROP_DEF
+    # don't want user to hide this component using an cwproperty
+    site_wide = True
     visible = False # disabled by default
-    
+
     def call(self):
         _ = self.req._
         self.w(u'<div id="etyperestriction">')
@@ -197,7 +213,7 @@
             html.insert(0, u'<span class="selected">%s</span>' % _('Any'))
         self.w(u'&nbsp;|&nbsp;'.join(html))
         self.w(u'</div>')
-        
+
 
 def registration_callback(vreg):
     vreg.register_all(globals().values(), __name__, (SeeAlsoVComponent,))
--- a/web/views/baseforms.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/baseforms.py	Tue Apr 28 19:12:52 2009 +0200
@@ -21,7 +21,7 @@
 from cubicweb.web.controller import NAV_FORM_PARAMETERS
 from cubicweb.web.widgets import checkbox, InputWidget, ComboBoxWidget
 from cubicweb.web.form import FormMixIn
-from cubicweb.web.views.editforms import AutomaticEntityForm
+from cubicweb.web.views.autoform import AutomaticEntityForm
 
 _ = unicode
     
--- a/web/views/baseviews.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/baseviews.py	Tue Apr 28 19:12:52 2009 +0200
@@ -14,13 +14,11 @@
 
 __docformat__ = "restructuredtext en"
 
-from warnings import warn
-
 from rql import nodes
 
 from logilab.mtconverter import TransformError, html_escape
 
-from cubicweb import Unauthorized, NoSelectableObject
+from cubicweb import NoSelectableObject
 from cubicweb.selectors import yes, empty_rset
 from cubicweb.view import EntityView, AnyRsetView, View
 from cubicweb.common.uilib import cut, printable_value
@@ -101,219 +99,6 @@
         self.wdata(printable_value(self.req, etype, value, props, displaytime=displaytime))
 
 
-PRIMARY_SKIP_RELS = set(['is', 'is_instance_of', 'identity',
-                         'owned_by', 'created_by',
-                         'in_state', 'wf_info_for', 'require_permission',
-                         'from_entity', 'to_entity',
-                         'see_also'])
-
-class PrimaryView(EntityView):
-    """the full view of an non final entity"""
-    id = 'primary'
-    title = _('primary')
-    show_attr_label = True
-    show_rel_label = True
-    skip_none = True
-    skip_attrs = ('eid', 'creation_date', 'modification_date')
-    skip_rels = ()
-    main_related_section = True
-
-    def html_headers(self):
-        """return a list of html headers (eg something to be inserted between
-        <head> and </head> of the returned page
-
-        by default primary views are indexed
-        """
-        return []
-
-    def cell_call(self, row, col):
-        self.row = row
-        # XXX move render_entity implementation here
-        self.render_entity(self.complete_entity(row, col))
-
-    def render_entity(self, entity):
-        """return html to display the given entity"""
-        siderelations = []
-        self.render_entity_title(entity)
-        self.render_entity_metadata(entity)
-        # entity's attributes and relations, excluding meta data
-        # if the entity isn't meta itself
-        boxes = self._preinit_side_related(entity, siderelations)
-        if boxes:
-            self.w(u'<table width="100%"><tr><td width="75%">')
-        self.w(u'<div>')
-        self.w(u'<div class="mainInfo">')
-        self.render_entity_attributes(entity, siderelations)
-        self.w(u'</div>')
-        self.content_navigation_components('navcontenttop')
-        if self.main_related_section:
-            self.render_entity_relations(entity, siderelations)
-        self.w(u'</div>')
-        if boxes:
-            self.w(u'</td><td>')
-            # side boxes
-            self.w(u'<div class="primaryRight">')
-            self.render_side_related(entity, siderelations)
-            self.w(u'</div>')
-            self.w(u'</td></tr></table>')
-        self.content_navigation_components('navcontentbottom')
-
-
-    def content_navigation_components(self, context):
-        self.w(u'<div class="%s">' % context)
-        for comp in self.vreg.possible_vobjects('contentnavigation',
-                                                self.req, self.rset, row=self.row,
-                                                view=self, context=context):
-            try:
-                comp.dispatch(w=self.w, row=self.row, view=self)
-            except NotImplementedError:
-                warn('component %s doesnt implement cell_call, please update'
-                     % comp.__class__, DeprecationWarning)
-                comp.dispatch(w=self.w, view=self)
-        self.w(u'</div>')
-
-    def iter_attributes(self, entity):
-        for rschema, targetschema in entity.e_schema.attribute_definitions():
-            if rschema.type in self.skip_attrs:
-                continue
-            yield rschema, targetschema
-
-    def iter_relations(self, entity):
-        skip = set(self.skip_rels)
-        skip.update(PRIMARY_SKIP_RELS)
-        for rschema, targetschemas, x in entity.e_schema.relation_definitions():
-            if rschema.type in skip:
-                continue
-            yield rschema, targetschemas, x
-
-    def render_entity_title(self, entity):
-        title = self.content_title(entity) # deprecate content_title?
-        if title:
-            self.w(u'<h1><span class="etype">%s</span> %s</h1>'
-                   % (entity.dc_type().capitalize(), title))
-
-    def content_title(self, entity):
-        """default implementation return an empty string"""
-        return u''
-
-    def render_entity_metadata(self, entity):
-        entity.view('metadata', w=self.w)
-        summary = self.summary(entity) # deprecate summary?
-        if summary:
-            self.w(u'<div class="summary">%s</div>' % summary)
-
-    def summary(self, entity):
-        """default implementation return an empty string"""
-        return u''
-
-    def render_entity_attributes(self, entity, siderelations):
-        for rschema, targetschema in self.iter_attributes(entity):
-            attr = rschema.type
-            if targetschema.type in ('Password', 'Bytes'):
-                continue
-            try:
-                wdg = entity.get_widget(attr)
-            except Exception, ex:
-                value = entity.printable_value(attr, entity[attr], targetschema.type)
-            else:
-                value = wdg.render(entity)
-            if self.skip_none and (value is None or value == ''):
-                continue
-            if rschema.meta:
-                continue
-            self._render_related_entities(entity, rschema, value)
-
-    def _preinit_side_related(self, entity, siderelations):
-        self._sideboxes = None
-        self._related_entities = []
-        if hasattr(self, 'get_side_boxes_defs'):
-            self._sideboxes = [(label, rset) for label, rset in self.get_side_boxes_defs(entity)
-                               if rset]
-        else:
-            eschema = entity.e_schema
-            maxrelated = self.req.property_value('navigation.related-limit')
-            for rschema, targetschemas, x in self.iter_relations(entity):
-                try:
-                    related = entity.related(rschema.type, x, limit=maxrelated+1)
-                except Unauthorized:
-                    continue
-                if not related:
-                    continue
-                if self.is_side_related(rschema, eschema):
-                    siderelations.append((rschema, related, x))
-                    continue
-                self._related_entities.append((rschema, related, x))
-        self._boxes_in_context = list(self.vreg.possible_vobjects('boxes', self.req, self.rset,
-                                                 row=self.row, view=self,
-                                                 context='incontext'))
-        return self._sideboxes or self._boxes_in_context or self._related_entities or siderelations
-
-    def render_entity_relations(self, entity, siderelations):
-        if self._related_entities:
-            for rschema, related, x in self._related_entities:
-                self._render_related_entities(entity, rschema, related, x)
-
-
-    def render_side_related(self, entity, siderelations):
-        """display side related relations:
-        non-meta in a first step, meta in a second step
-        """
-        if self._sideboxes:
-            for label, rset in self._sideboxes:
-                self.w(u'<div class="sideRelated">')
-                self.wview('sidebox', rset, title=label)
-                self.w(u'</div>')
-        elif siderelations:
-            self.w(u'<div class="sideRelated">')
-            for relatedinfos in siderelations:
-                # if not relatedinfos[0].meta:
-                #    continue
-                self._render_related_entities(entity, *relatedinfos)
-            self.w(u'</div>')
-
-        if self._boxes_in_context:
-            for box in self._boxes_in_context:
-                try:
-                    box.dispatch(w=self.w, row=self.row)
-                except NotImplementedError:
-                    # much probably a context insensitive box, which only implements
-                    # .call() and not cell_call()
-                    box.dispatch(w=self.w)
-
-    def is_side_related(self, rschema, eschema):
-        return rschema.meta and \
-               not rschema.schema_relation() == eschema.schema_entity()
-
-    def _render_related_entities(self, entity, rschema, related,
-                                 role='subject'):
-        if rschema.is_final():
-            value = related
-            show_label = self.show_attr_label
-        else:
-            if not related:
-                return
-            show_label = self.show_rel_label
-            # if not too many entities, show them all in a list
-            maxrelated = self.req.property_value('navigation.related-limit')
-            if related.rowcount <= maxrelated:
-                if related.rowcount == 1:
-                    value = self.view('incontext', related, row=0)
-                elif 1 < related.rowcount <= 5:
-                    value = self.view('csv', related)
-                else:
-                    value = '<div>' + self.view('simplelist', related) + '</div>'
-            # else show links to display related entities
-            else:
-                rql = related.printable_rql()
-                related.limit(maxrelated)
-                value = '<div>' + self.view('simplelist', related)
-                value += '[<a href="%s">%s</a>]' % (self.build_url(rql=rql),
-                                                    self.req._('see them all'))
-                value +=  '</div>'
-        label = display_name(self.req, rschema.type, role)
-        self.field(label, value, show_label=show_label, tr=False)
-
-
 class SecondaryView(EntityView):
     id = 'secondary'
     title = _('secondary')
@@ -586,7 +371,9 @@
 except ImportError:
     pass # gae has no tableview module (yet)
 
-from cubicweb.web.views import boxes, xmlrss
+from cubicweb.web.views import boxes, xmlrss, primary
+PrimaryView = class_moved(primary.PrimaryView)
+PRIMARY_SKIP_RELS = primary.PRIMARY_SKIP_RELS
 SideBoxView = class_moved(boxes.SideBoxView)
 XmlView = class_moved(xmlrss.XmlView)
 XmlItemView = class_moved(xmlrss.XmlItemView)
--- a/web/views/bookmark.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/bookmark.py	Tue Apr 28 19:12:52 2009 +0200
@@ -11,13 +11,11 @@
 from cubicweb import Unauthorized
 from cubicweb.selectors import implements
 from cubicweb.web.htmlwidgets import BoxWidget, BoxMenu, RawBoxItem
-from cubicweb.web import action, formwidgets
-from cubicweb.web.box import UserRQLBoxTemplate
+from cubicweb.web import uicfg, action, box, formwidgets
 from cubicweb.web.views.baseviews import PrimaryView
-from cubicweb.web.views.editforms import AutomaticEntityForm
 
-AutomaticEntityForm.rcategories.set_rtag('primary', 'path', 'subject', 'Bookmark')
-AutomaticEntityForm.rwidgets.set_rtag(formwidgets.TextInput, 'path', 'subject', 'Bookmark')
+uicfg.rcategories.set_rtag('primary', 'path', 'subject', 'Bookmark')
+uicfg.rwidgets.set_rtag(formwidgets.TextInput, 'path', 'subject', 'Bookmark')
 
 
 class FollowAction(action.Action):
@@ -26,14 +24,14 @@
 
     title = _('follow')
     category = 'mainactions'
-    
+
     def url(self):
         return self.rset.get_entity(self.row or 0, self.col or 0).actual_url()
 
 
 class BookmarkPrimaryView(PrimaryView):
     __select__ = implements('Bookmark')
-        
+
     def cell_call(self, row, col):
         """the primary view for bookmark entity"""
         entity = self.complete_entity(row, col)
@@ -49,7 +47,7 @@
         self.w(u'</div>')
 
 
-class BookmarksBox(UserRQLBoxTemplate):
+class BookmarksBox(box.UserRQLBoxTemplate):
     """display a box containing all user's bookmarks"""
     id = 'bookmarks_box'
     order = 40
@@ -59,8 +57,8 @@
            'U eid %(x)s')
     etype = 'Bookmark'
     rtype = 'bookmarked_by'
-    
-    
+
+
     def call(self, **kwargs):
         req = self.req
         ueid = req.user.eid
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/views/cwproperties.py	Tue Apr 28 19:12:52 2009 +0200
@@ -0,0 +1,329 @@
+"""Specific views for CWProperty
+
+:organization: Logilab
+:copyright: 2007-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+"""
+__docformat__ = "restructuredtext en"
+
+from logilab.mtconverter import html_escape
+
+from logilab.common.decorators import cached
+
+from cubicweb import UnknownProperty
+from cubicweb.selectors import (one_line_rset, none_rset, implements,
+                                match_user_groups, entity_implements)
+from cubicweb.utils import UStringIO
+from cubicweb.view import StartupView
+from cubicweb.web import INTERNAL_FIELD_VALUE, eid_param, uicfg
+from cubicweb.web.views import baseviews
+from cubicweb.web import stdmsgs
+from cubicweb.web.form import CompositeForm, EntityFieldsForm, FormViewMixIn
+from cubicweb.web.formfields import FIELDS, StringField
+from cubicweb.web.formwidgets import Select, Button, SubmitButton
+
+_ = unicode
+
+# some string we want to be internationalizable for nicer display of eproperty
+# groups
+_('navigation')
+_('ui')
+_('actions')
+_('boxes')
+_('components')
+_('contentnavigation')
+
+
+def make_togglable_link(nodeid, label, cookiename):
+    """builds a HTML link that switches the visibility & remembers it"""
+    action = u"javascript: toggle_and_remember_visibility('%s', '%s')" % \
+        (nodeid, cookiename)
+    return u'<a href="%s">%s</a>' % (action, label)
+
+def css_class(someclass):
+    return someclass and 'class="%s"' % someclass or ''
+
+
+class CWPropertyPrimaryView(baseviews.PrimaryView):
+    __select__ = implements('CWProperty')
+    skip_none = False
+
+
+class SystemEPropertiesForm(FormViewMixIn, StartupView):
+    id = 'systemepropertiesform'
+    __select__ = none_rset() & match_user_groups('managers')
+
+    title = _('site configuration')
+    category = 'startupview'
+
+    def linkable(self):
+        return True
+
+    def url(self):
+        """return the url associated with this view. We can omit rql here"""
+        return self.build_url('view', vid=self.id)
+
+    def _cookie_name(self, somestr):
+        return str('%s_property_%s' % (self.config.appid, somestr))
+
+    def _group_status(self, group, default=u'hidden'):
+        """return css class name 'hidden' (collapsed), or '' (open)"""
+        cookies = self.req.get_cookie()
+        cookiename = self._cookie_name(group)
+        cookie = cookies.get(cookiename)
+        if cookie is None:
+            cookies[cookiename] = default
+            self.req.set_cookie(cookies, cookiename, maxage=None)
+            status = default
+        else:
+            status = cookie.value
+        return status
+
+    def call(self, **kwargs):
+        """The default view representing the application's index"""
+        self.req.add_js('cubicweb.preferences.js')
+        self.req.add_css('cubicweb.preferences.css')
+        vreg = self.vreg
+        values = self.defined_keys
+        groupedopts = {}
+        mainopts = {}
+        # "self.id=='systemepropertiesform'" to skip site wide properties on
+        # user's preference but not site's configuration
+        for key in vreg.user_property_keys(self.id=='systemepropertiesform'):
+            parts = key.split('.')
+            if parts[0] in vreg:
+                # appobject configuration
+                reg, oid, propid = parts
+                groupedopts.setdefault(reg, {}).setdefault(oid, []).append(key)
+            else:
+                mainopts.setdefault(parts[0], []).append(key)
+        # precompute form to consume error message
+        for group, keys in mainopts.items():
+            mainopts[group] = self.form(keys, True)
+        for group, objects in groupedopts.items():
+            for oid, keys in objects.items():
+                groupedopts[group][oid] = self.form(keys, True)
+        w = self.w
+        req = self.req
+        _ = req._
+        w(u'<h1>%s</h1>\n' % _(self.title))
+        # we don't want this in each sub-forms
+        w(u'<div id="progress">%s</div>' % self.req._('validating...'))
+        for label, group, form in sorted((_(g), g, f)
+                                         for g, f in mainopts.iteritems()):
+            status = css_class(self._group_status(group))
+            w(u'<h2 class="propertiesform">%s</h2>\n' %
+              (make_togglable_link('fieldset_' + group, label,
+                                   self._cookie_name(group))))
+            w(u'<div id="fieldset_%s" %s>' % (group, status))
+            w(form)
+            w(u'</div>')
+        for label, group, objects in sorted((_(g), g, o)
+                                            for g, o in groupedopts.iteritems()):
+            status = css_class(self._group_status(group))
+            w(u'<h2 class="propertiesform">%s</h2>\n' %
+              (make_togglable_link('fieldset_' + group, label,
+                                   self._cookie_name(group))))
+            w(u'<div id="fieldset_%s" %s>' % (group, status))
+            for label, oid, form in sorted((self.req.__('%s_%s' % (group, o)), o, f)
+                                           for o, f in objects.iteritems()):
+                w(u'<fieldset class="subentity">')
+                w(u'<legend class="componentTitle">%s</legend>\n' % label)
+                docmsgid = '%s_%s_description' % (group, oid)
+                doc = _(docmsgid)
+                if doc != docmsgid:
+                    w(u'<p class="description">%s</p>' % html_escape(doc))
+                w(form)
+                w(u'</fieldset>')
+            w(u'</div>')
+
+    @property
+    @cached
+    def eprops_rset(self):
+        return self.req.execute('Any P,K,V WHERE P is CWProperty, P pkey K, '
+                                'P value V, NOT P for_user U')
+
+    @property
+    def defined_keys(self):
+        values = {}
+        for i, entity in enumerate(self.eprops_rset.entities()):
+            values[entity.pkey] = i
+        return values
+
+    def entity_for_key(self, key):
+        values = self.defined_keys
+        if key in values:
+            entity = self.eprops_rset.get_entity(values[key], 0)
+        else:
+            entity = self.vreg.etype_class('CWProperty')(self.req, None, None)
+            entity.eid = self.req.varmaker.next()
+            entity['pkey'] = key
+            entity['value'] = self.vreg.property_value(key)
+        return entity
+
+    def form(self, keys, splitlabel=False):
+        buttons = [SubmitButton(),
+                   Button(stdmsgs.BUTTON_CANCEL, cwaction='cancel')]
+        form = CompositeForm(self.req, domid=None, action=self.build_url(),
+                             form_buttons=buttons,
+                             submitmsg=self.req._('changes applied'))
+        path = self.req.relative_path()
+        if '?' in path:
+            path, params = path.split('?', 1)
+            form.form_add_hidden('__redirectparams', params)
+        form.form_add_hidden('__redirectpath', path)
+        for key in keys:
+            self.form_row(form, key, splitlabel)
+        return form.form_render(display_progress_div=False)
+
+    def form_row(self, form, key, splitlabel):
+        entity = self.entity_for_key(key)
+        if splitlabel:
+            label = key.split('.')[-1]
+        else:
+            label = key
+        subform = EntityFieldsForm(self.req, entity=entity, set_error_url=False)
+        subform.append_field(PropertyValueField(name='value', label=label,
+                                                eidparam=True))
+        subform.vreg = self.vreg
+        subform.form_add_hidden('pkey', key, eidparam=True)
+        form.form_add_subform(subform)
+        return subform
+
+
+def is_user_prefs(cls, req, rset, row=None, col=0, **kwargs):
+    return req.user.eid == rset[row or 0][col]
+
+
+class EPropertiesForm(SystemEPropertiesForm):
+    id = 'epropertiesform'
+    __select__ = (
+        # we don't want guests to be able to come here
+        match_user_groups('users', 'managers') &
+        (none_rset() | ((one_line_rset() & is_user_prefs) &
+                        (one_line_rset() & match_user_groups('managers'))))
+        )
+
+    title = _('preferences')
+
+    @property
+    def user(self):
+        if self.rset is None:
+            return self.req.user
+        return self.rset.get_entity(self.row or 0, self.col or 0)
+
+    @property
+    @cached
+    def eprops_rset(self):
+        return self.req.execute('Any P,K,V WHERE P is CWProperty, P pkey K, P value V,'
+                                'P for_user U, U eid %(x)s', {'x': self.user.eid})
+
+    def form_row(self, form, key, splitlabel):
+        subform = super(EPropertiesForm, self).form_row(form, key, splitlabel)
+        # if user is in the managers group and the property is being created,
+        # we have to set for_user explicitly
+        if not subform.edited_entity.has_eid() and self.user.matching_groups('managers'):
+            subform.form_add_hidden('for_user', self.user.eid, eidparam=True)
+
+
+# eproperty form objects ######################################################
+
+class PlaceHolderWidget(object):
+
+    def render(self, form, field):
+        domid = form.context[field]['id']
+        # empty span as well else html validation fail (label is refering to
+        # this id)
+        return '<div id="div:%s"><span id="%s">%s</span></div>' % (
+            domid, domid, form.req._('select a key first'))
+
+
+class NotEditableWidget(object):
+    def __init__(self, value, msg=None):
+        self.value = value
+        self.msg = msg
+
+    def render(self, form, field):
+        domid = form.context[field]['id']
+        value = '<span class="value" id="%s">%s</span>' % (domid, self.value)
+        if self.msg:
+            value + '<div class="helper">%s</div>' % self.msg
+        return value
+
+
+class PropertyKeyField(StringField):
+    """specific field for CWProperty.pkey to set the value widget according to
+    the selected key
+    """
+    widget = Select
+
+    def render(self, form, renderer):
+        wdg = self.get_widget(form)
+        wdg.attrs['tabindex'] = form.req.next_tabindex()
+        wdg.attrs['onchange'] = "javascript:setPropValueWidget('%s', %s)" % (
+            form.edited_entity.eid, form.req.next_tabindex())
+        return wdg.render(form, self)
+
+    def vocabulary(self, form):
+        entity = form.edited_entity
+        _ = form.req._
+        if entity.has_eid():
+            return [(_(entity.pkey), entity.pkey)]
+        # key beginning with 'system.' should usually not be edited by hand
+        choices = entity.vreg.user_property_keys()
+        return [(u'', u'')] + sorted(zip((_(v) for v in choices), choices))
+
+
+class PropertyValueField(StringField):
+    """specific field for CWProperty.value  which will be different according to
+    the selected key type and vocabulary information
+    """
+    widget = PlaceHolderWidget
+
+    def render(self, form, renderer=None, tabindex=None):
+        wdg = self.get_widget(form)
+        if tabindex is not None:
+            wdg.attrs['tabindex'] = tabindex
+        return wdg.render(form, self)
+
+    def form_init(self, form):
+        entity = form.edited_entity
+        if not (entity.has_eid() or 'pkey' in entity):
+            # no key set yet, just include an empty div which will be filled
+            # on key selection
+            return
+        try:
+            pdef = form.vreg.property_info(entity.pkey)
+        except UnknownProperty, ex:
+            self.warning('%s (you should probably delete that property '
+                         'from the database)', ex)
+            msg = form.req._('you should probably delete that property')
+            self.widget = NotEditableWidget(entity.printable_value('value'),
+                                            '%s (%s)' % (msg, ex))
+        if entity.pkey.startswith('system.'):
+            msg = form.req._('value associated to this key is not editable '
+                             'manually')
+            self.widget = NotEditableWidget(entity.printable_value('value'), msg)
+        # XXX race condition when used from CWPropertyForm, should not rely on
+        # instance attributes
+        self.initial = pdef['default']
+        self.help = pdef['help']
+        vocab = pdef['vocabulary']
+        if vocab is not None:
+            if callable(vocab):
+                # list() just in case its a generator function
+                self.choices = list(vocab(form.req))
+            else:
+                self.choices = vocab
+            wdg = Select()
+        else:
+            wdg = FIELDS[pdef['type']].widget()
+            if pdef['type'] == 'Boolean':
+                self.choices = [(form.req._('yes'), '1'), (form.req._('no'), '')]
+            elif pdef['type'] in ('Float', 'Int'):
+                wdg.attrs.setdefault('size', 3)
+        self.widget = wdg
+
+uicfg.rfields.set_rtag(PropertyKeyField, 'pkey', 'subject', 'CWProperty')
+uicfg.rfields.set_rtag(PropertyValueField, 'value', 'subject', 'CWProperty')
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/views/cwuser.py	Tue Apr 28 19:12:52 2009 +0200
@@ -0,0 +1,102 @@
+"""Specific views for users
+
+:organization: Logilab
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+"""
+__docformat__ = "restructuredtext en"
+
+from logilab.mtconverter import html_escape
+
+from cubicweb.selectors import one_line_rset, implements, match_user_groups
+from cubicweb.view import EntityView
+from cubicweb.web import uicfg, action
+from cubicweb.web.views.baseviews import PrimaryView
+
+
+uicfg.rcategories.set_rtag('secondary', 'firstname', 'subject', 'CWUser')
+uicfg.rcategories.set_rtag('secondary', 'surname', 'subject', 'CWUser')
+uicfg.rcategories.set_rtag('metadata', 'last_login_time', 'subject', 'CWUser')
+uicfg.rcategories.set_rtag('primary', 'in_group', 'subject', 'CWUser')
+uicfg.rcategories.set_rtag('generated', 'owned_by', 'object', otype='CWUser')
+uicfg.rcategories.set_rtag('generated', 'created_by', 'object', otype='CWUser')
+uicfg.rcategories.set_rtag('metadata', 'bookmarked_by', 'object', otype='CWUser')
+uicfg.rinlined.set_rtag(True, 'use_email', 'subject', 'CWUser')
+uicfg.rmode.set_rtag('create', 'in_group', 'object', otype='CWGroup')
+uicfg.rmode.set_rtag('link', 'owned_by', 'object', otype='CWUser')
+uicfg.rmode.set_rtag('link', 'created_by', 'object', otype='CWUser')
+uicfg.rmode.set_rtag('create', 'bookmarked_by', 'object', otype='CWUser')
+
+
+class UserPreferencesEntityAction(action.Action):
+    id = 'prefs'
+    __select__ = (one_line_rset() & implements('CWUser') &
+                  match_user_groups('owners', 'managers'))
+
+    title = _('preferences')
+    category = 'mainactions'
+
+    def url(self):
+        login = self.rset.get_entity(self.row or 0, self.col or 0).login
+        return self.build_url('euser/%s'%login, vid='epropertiesform')
+
+
+class CWUserPrimaryView(PrimaryView):
+    __select__ = implements('CWUser')
+
+    skip_attrs = ('firstname', 'surname')
+
+    def iter_relations(self, entity):
+        # don't want to display user's entities
+        for rschema, targetschemas, x in super(CWUserPrimaryView, self).iter_relations(entity):
+            if x == 'object' and rschema.type in ('owned_by', 'for_user'):
+                continue
+            yield rschema, targetschemas, x
+
+    def content_title(self, entity):
+        return entity.name()
+
+    def is_side_related(self, rschema, eschema):
+        # XXX only bookmarked_by defined in cw...
+        return  rschema.type in ['interested_in', 'tags',
+                                 'todo_by', 'bookmarked_by']
+
+
+class FoafView(EntityView):
+    id = 'foaf'
+    __select__ = implements('CWUser')
+
+    title = _('foaf')
+    templatable = False
+    content_type = 'text/xml'
+
+    def call(self):
+        self.w(u'''<?xml version="1.0" encoding="%s"?>
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+         xmlns:rdfs="http://www.w3org/2000/01/rdf-schema#"
+         xmlns:foaf="http://xmlns.com/foaf/0.1/"> '''% self.req.encoding)
+        for i in xrange(self.rset.rowcount):
+            self.cell_call(i, 0)
+        self.w(u'</rdf:RDF>\n')
+
+    def cell_call(self, row, col):
+        entity = self.complete_entity(row, col)
+        self.w(u'''<foaf:PersonalProfileDocument rdf:about="">
+                      <foaf:maker rdf:resource="%s"/>
+                      <foaf:primaryTopic rdf:resource="%s"/>
+                   </foaf:PersonalProfileDocument>''' % (entity.absolute_url(), entity.absolute_url()))
+        self.w(u'<foaf:Person rdf:ID="%s">\n' % entity.eid)
+        self.w(u'<foaf:name>%s</foaf:name>\n' % html_escape(entity.dc_long_title()))
+        if entity.surname:
+            self.w(u'<foaf:family_name>%s</foaf:family_name>\n'
+                   % html_escape(entity.surname))
+        if entity.firstname:
+            self.w(u'<foaf:givenname>%s</foaf:givenname>\n'
+                   % html_escape(entity.firstname))
+        emailaddr = entity.get_email()
+        if emailaddr:
+            self.w(u'<foaf:mbox>%s</foaf:mbox>\n' % html_escape(emailaddr))
+        self.w(u'</foaf:Person>\n')
+
+from logilab.common.deprecation import class_renamed
+EUserPrimaryView = class_renamed('EUserPrimaryView', CWUserPrimaryView)
--- a/web/views/editforms.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/editforms.py	Tue Apr 28 19:12:52 2009 +0200
@@ -11,23 +11,20 @@
 
 from simplejson import dumps
 
-from logilab.common.decorators import iclassmethod
 from logilab.mtconverter import html_escape
 
-from cubicweb import typed_eid
 from cubicweb.selectors import (match_kwargs, one_line_rset, non_final_entity,
                                 specified_etype_implements, yes)
 from cubicweb.utils import make_uid
 from cubicweb.view import EntityView
 from cubicweb.common import tags
-from cubicweb.web import INTERNAL_FIELD_VALUE, stdmsgs, uicfg
-from cubicweb.web.form import (FieldNotFound, CompositeForm, EntityFieldsForm,
-                               FormViewMixIn)
-from cubicweb.web.formfields import guess_field
+from cubicweb.web import stdmsgs
+from cubicweb.web.form import CompositeForm, EntityFieldsForm, FormViewMixIn
 from cubicweb.web.formwidgets import Button, SubmitButton, ResetButton
 from cubicweb.web.formrenderers import (FormRenderer, EntityFormRenderer,
                                         EntityCompositeFormRenderer,
                                         EntityInlinedFormRenderer)
+
 _ = unicode
 
 def relation_id(eid, rtype, role, reid):
@@ -125,317 +122,6 @@
         self.w(form.form_render(renderer=renderer))
 
 
-class AutomaticEntityForm(EntityFieldsForm):
-    """base automatic form to edit any entity
-
-    Designed to be flly generated from schema but highly configurable through:
-    * rtags (rcategories, rfields, rwidgets, inlined, rpermissions)
-    * various standard form parameters
-
-    You can also easily customise it by adding/removing fields in
-    AutomaticEntityForm instances.
-    """
-    id = 'edition'
-
-    cwtarget = 'eformframe'
-    cssclass = 'entityForm'
-    copy_nav_params = True
-    form_buttons = [SubmitButton(stdmsgs.BUTTON_OK),
-                    Button(stdmsgs.BUTTON_APPLY, cwaction='apply'),
-                    Button(stdmsgs.BUTTON_CANCEL, cwaction='cancel')]
-    attrcategories = ('primary', 'secondary')
-    # class attributes below are actually stored in the uicfg module since we
-    # don't want them to be reloaded
-    rcategories = uicfg.rcategories
-    rfields = uicfg.rfields
-    rwidgets = uicfg.rwidgets
-    rinlined = uicfg.rinlined
-    rpermissions_overrides = uicfg.rpermissions_overrides
-
-    @classmethod
-    def vreg_initialization_completed(cls):
-        """set default category tags for relations where it's not yet defined in
-        the category relation tags
-        """
-        for eschema in cls.schema.entities():
-            for rschema, tschemas, role in eschema.relation_definitions(True):
-                for tschema in tschemas:
-                    if role == 'subject':
-                        X, Y = eschema, tschema
-                        card = rschema.rproperty(X, Y, 'cardinality')[0]
-                        composed = rschema.rproperty(X, Y, 'composite') == 'object'
-                    else:
-                        X, Y = tschema, eschema
-                        card = rschema.rproperty(X, Y, 'cardinality')[1]
-                        composed = rschema.rproperty(X, Y, 'composite') == 'subject'
-                    if not cls.rcategories.rtag(rschema, role, X, Y):
-                        if card in '1+':
-                            if not rschema.is_final() and composed:
-                                category = 'generated'
-                            else:
-                                category = 'primary'
-                        elif rschema.is_final():
-                            category = 'secondary'
-                        else:
-                            category = 'generic'
-                        cls.rcategories.set_rtag(category, rschema, role, X, Y)
-
-    @classmethod
-    def erelations_by_category(cls, entity, categories=None, permission=None, rtags=None):
-        """return a list of (relation schema, target schemas, role) matching
-        categories and permission
-        """
-        if categories is not None:
-            if not isinstance(categories, (list, tuple, set, frozenset)):
-                categories = (categories,)
-            if not isinstance(categories, (set, frozenset)):
-                categories = frozenset(categories)
-        eschema  = entity.e_schema
-        if rtags is None:
-            rtags = cls.rcategories
-        permsoverrides = cls.rpermissions_overrides
-        if entity.has_eid():
-            eid = entity.eid
-        else:
-            eid = None
-        for rschema, targetschemas, role in eschema.relation_definitions(True):
-            # check category first, potentially lower cost than checking
-            # permission which may imply rql queries
-            if categories is not None:
-                targetschemas = [tschema for tschema in targetschemas
-                                 if rtags.etype_rtag(eschema, rschema, role, tschema) in categories]
-                if not targetschemas:
-                    continue
-            if permission is not None:
-                # tag allowing to hijack the permission machinery when
-                # permission is not verifiable until the entity is actually
-                # created...
-                if eid is None and '%s_on_new' % permission in permsoverrides.etype_rtags(eschema, rschema, role):
-                    yield (rschema, targetschemas, role)
-                    continue
-                if rschema.is_final():
-                    if not rschema.has_perm(entity.req, permission, eid):
-                        continue
-                elif role == 'subject':
-                    if not ((eid is None and rschema.has_local_role(permission)) or
-                            rschema.has_perm(entity.req, permission, fromeid=eid)):
-                        continue
-                    # on relation with cardinality 1 or ?, we need delete perm as well
-                    # if the relation is already set
-                    if (permission == 'add'
-                        and rschema.cardinality(eschema, targetschemas[0], role) in '1?'
-                        and eid and entity.related(rschema.type, role)
-                        and not rschema.has_perm(entity.req, 'delete', fromeid=eid,
-                                                 toeid=entity.related(rschema.type, role)[0][0])):
-                        continue
-                elif role == 'object':
-                    if not ((eid is None and rschema.has_local_role(permission)) or
-                            rschema.has_perm(entity.req, permission, toeid=eid)):
-                        continue
-                    # on relation with cardinality 1 or ?, we need delete perm as well
-                    # if the relation is already set
-                    if (permission == 'add'
-                        and rschema.cardinality(targetschemas[0], eschema, role) in '1?'
-                        and eid and entity.related(rschema.type, role)
-                        and not rschema.has_perm(entity.req, 'delete', toeid=eid,
-                                                 fromeid=entity.related(rschema.type, role)[0][0])):
-                        continue
-            yield (rschema, targetschemas, role)
-
-    @classmethod
-    def esrelations_by_category(cls, entity, categories=None, permission=None):
-        """filter out result of relations_by_category(categories, permission) by
-        removing final relations
-
-        return a sorted list of (relation's label, relation'schema, role)
-        """
-        result = []
-        for rschema, ttypes, role in cls.erelations_by_category(
-            entity, categories, permission):
-            if rschema.is_final():
-                continue
-            result.append((rschema.display_name(entity.req, role), rschema, role))
-        return sorted(result)
-
-    @iclassmethod
-    def field_by_name(cls_or_self, name, role='subject', eschema=None):
-        """return field with the given name and role. If field is not explicitly
-        defined for the form but `eclass` is specified, guess_field will be
-        called.
-        """
-        try:
-            return super(AutomaticEntityForm, cls_or_self).field_by_name(name, role)
-        except FieldNotFound: # XXX should raise more explicit exception
-            if eschema is None or not name in cls_or_self.schema:
-                raise
-            rschema = cls_or_self.schema.rschema(name)
-            fieldcls = cls_or_self.rfields.etype_rtag(eschema, rschema, role)
-            if fieldcls:
-                return fieldcls(name=name, role=role, eidparam=True)
-            widget = cls_or_self.rwidgets.etype_rtag(eschema, rschema, role)
-            if widget:
-                field = guess_field(eschema, rschema, role,
-                                    eidparam=True, widget=widget)
-            else:
-                field = guess_field(eschema, rschema, role, eidparam=True)
-            if field is None:
-                raise
-            return field
-
-    def __init__(self, *args, **kwargs):
-        super(AutomaticEntityForm, self).__init__(*args, **kwargs)
-        entity = self.edited_entity
-        if entity.has_eid():
-            entity.complete()
-        for rschema, role in self.editable_attributes():
-            try:
-                self.field_by_name(rschema.type, role)
-                continue # explicitly specified
-            except FieldNotFound:
-                # has to be guessed
-                try:
-                    field = self.field_by_name(rschema.type, role,
-                                               eschema=entity.e_schema)
-                    self.fields.append(field)
-                except FieldNotFound:
-                    # meta attribute such as <attr>_format
-                    continue
-        self.maxrelitems = self.req.property_value('navigation.related-limit')
-        self.force_display = bool(self.req.form.get('__force_display'))
-
-    @property
-    def related_limit(self):
-        if self.force_display:
-            return None
-        return self.maxrelitems + 1
-
-    def relations_by_category(self, categories=None, permission=None):
-        """return a list of (relation schema, target schemas, role) matching
-        given category(ies) and permission
-        """
-        return self.erelations_by_category(self.edited_entity, categories,
-                                           permission)
-
-    def inlined_relations(self):
-        """return a list of (relation schema, target schemas, role) matching
-        given category(ies) and permission
-        """
-        # we'll need an initialized varmaker if there are some inlined relation
-        self.initialize_varmaker()
-        return self.erelations_by_category(self.edited_entity, True, 'add', self.rinlined)
-
-    def srelations_by_category(self, categories=None, permission=None):
-        """filter out result of relations_by_category(categories, permission) by
-        removing final relations
-
-        return a sorted list of (relation's label, relation'schema, role)
-        """
-        return self.esrelations_by_category(self.edited_entity, categories,
-                                           permission)
-
-    def action(self):
-        """return the form's action attribute. Default to validateform if not
-        explicitly overriden.
-        """
-        try:
-            return self._action
-        except AttributeError:
-            return self.build_url('validateform')
-
-    def set_action(self, value):
-        """override default action"""
-        self._action = value
-
-    action = property(action, set_action)
-
-    def editable_attributes(self):
-        """return a list of (relation schema, role) to edit for the entity"""
-        return [(rschema, x) for rschema, _, x in self.relations_by_category(
-            self.attrcategories, 'add') if rschema != 'eid']
-
-    def relations_table(self):
-        """yiels 3-tuples (rtype, target, related_list)
-        where <related_list> itself a list of :
-          - node_id (will be the entity element's DOM id)
-          - appropriate javascript's togglePendingDelete() function call
-          - status 'pendingdelete' or ''
-          - oneline view of related entity
-        """
-        entity = self.edited_entity
-        pending_deletes = self.req.get_pending_deletes(entity.eid)
-        for label, rschema, role in self.srelations_by_category('generic', 'add'):
-            relatedrset = entity.related(rschema, role, limit=self.related_limit)
-            if rschema.has_perm(self.req, 'delete'):
-                toggable_rel_link_func = toggable_relation_link
-            else:
-                toggable_rel_link_func = lambda x, y, z: u''
-            related = []
-            for row in xrange(relatedrset.rowcount):
-                nodeid = relation_id(entity.eid, rschema, role,
-                                     relatedrset[row][0])
-                if nodeid in pending_deletes:
-                    status = u'pendingDelete'
-                    label = '+'
-                else:
-                    status = u''
-                    label = 'x'
-                dellink = toggable_rel_link_func(entity.eid, nodeid, label)
-                eview = self.view('oneline', relatedrset, row=row)
-                related.append((nodeid, dellink, status, eview))
-            yield (rschema, role, related)
-
-    def restore_pending_inserts(self, cell=False):
-        """used to restore edition page as it was before clicking on
-        'search for <some entity type>'
-        """
-        eid = self.edited_entity.eid
-        cell = cell and "div_insert_" or "tr"
-        pending_inserts = set(self.req.get_pending_inserts(eid))
-        for pendingid in pending_inserts:
-            eidfrom, rtype, eidto = pendingid.split(':')
-            if typed_eid(eidfrom) == eid: # subject
-                label = display_name(self.req, rtype, 'subject')
-                reid = eidto
-            else:
-                label = display_name(self.req, rtype, 'object')
-                reid = eidfrom
-            jscall = "javascript: cancelPendingInsert('%s', '%s', null, %s);" \
-                     % (pendingid, cell, eid)
-            rset = self.req.eid_rset(reid)
-            eview = self.view('text', rset, row=0)
-            # XXX find a clean way to handle baskets
-            if rset.description[0][0] == 'Basket':
-                eview = '%s (%s)' % (eview, display_name(self.req, 'Basket'))
-            yield rtype, pendingid, jscall, label, reid, eview
-
-    # should_* method extracted to allow overriding
-
-    def should_inline_relation_form(self, rschema, targettype, role):
-        """return true if the given relation with entity has role and a
-        targettype target should be inlined
-        """
-        return self.rinlined.etype_rtag(self.edited_entity.id, rschema, role, targettype)
-
-    def should_display_inline_creation_form(self, rschema, existant, card):
-        """return true if a creation form should be inlined
-
-        by default true if there is no related entity and we need at least one
-        """
-        return not existant and card in '1+'
-
-    def should_display_add_new_relation_link(self, rschema, existant, card):
-        """return true if we should add a link to add a new creation form
-        (through ajax call)
-
-        by default true if there is no related entity or if the relation has
-        multiple cardinality
-        """
-        return not existant or card in '+*'
-
-def etype_relation_field(etype, rtype, role='subject'):
-    eschema = AutomaticEntityForm.schema.eschema(etype)
-    return AutomaticEntityForm.field_by_name(rtype, role, eschema)
-
 class EditionFormView(FormViewMixIn, EntityView):
     """display primary entity edition form"""
     id = 'edition'
--- a/web/views/emailaddress.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/emailaddress.py	Tue Apr 28 19:12:52 2009 +0200
@@ -11,16 +11,15 @@
 from cubicweb.selectors import implements
 from cubicweb.common import Unauthorized
 from cubicweb.web.views import baseviews
-from cubicweb.web.views.editforms import AutomaticEntityForm
 
 
 class EmailAddressPrimaryView(baseviews.PrimaryView):
     __select__ = implements('EmailAddress')
-    
+
     def cell_call(self, row, col, skipeids=None):
         self.skipeids = skipeids
         super(EmailAddressPrimaryView, self).cell_call(row, col)
-        
+
     def render_entity_attributes(self, entity, siderelations):
         self.w(u'<h3>')
         entity.view('oneline', w=self.w)
@@ -70,10 +69,10 @@
         entity.view('oneline', w=self.w)
         self.w(u'</h5>')
 
-    
+
 class EmailAddressOneLineView(baseviews.OneLineView):
     __select__ = implements('EmailAddress')
-    
+
     def cell_call(self, row, col, **kwargs):
         entity = self.entity(row, col)
         if entity.reverse_primary_email:
@@ -93,7 +92,7 @@
 
     id = 'mailto'
     __select__ = implements('EmailAddress')
-    
+
     def cell_call(self, row, col, **kwargs):
         entity = self.entity(row, col)
         if entity.reverse_primary_email:
@@ -108,15 +107,15 @@
             mailto = "mailto:%s" % entity.display_address()
         self.w(u'<a href="%s">%s</a>' % (html_escape(mailto),
                                          html_escape(entity.display_address())))
-            
+
         if entity.alias:
             self.w(u'&gt;\n')
         if entity.reverse_primary_email:
             self.w(u'</b>')
 
-    
+
 class EmailAddressTextView(baseviews.TextView):
     __select__ = implements('EmailAddress')
-    
+
     def cell_call(self, row, col, **kwargs):
         self.w(self.entity(row, col).display_address())
--- a/web/views/eproperties.py	Tue Apr 28 13:28:37 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,330 +0,0 @@
-"""Specific views for CWProperty
-
-:organization: Logilab
-:copyright: 2007-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
-:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
-"""
-__docformat__ = "restructuredtext en"
-
-from logilab.mtconverter import html_escape
-
-from logilab.common.decorators import cached
-
-from cubicweb import UnknownProperty
-from cubicweb.selectors import (one_line_rset, none_rset, implements,
-                                match_user_groups, entity_implements)
-from cubicweb.utils import UStringIO
-from cubicweb.view import StartupView
-from cubicweb.web import INTERNAL_FIELD_VALUE, eid_param, uicfg
-from cubicweb.web.views import baseviews
-from cubicweb.web import stdmsgs
-from cubicweb.web.form import CompositeForm, EntityFieldsForm, FormViewMixIn
-from cubicweb.web.formfields import FIELDS, StringField
-from cubicweb.web.formwidgets import Select, Button, SubmitButton
-from cubicweb.web.views.editforms import AutomaticEntityForm
-
-_ = unicode
-
-# some string we want to be internationalizable for nicer display of eproperty
-# groups
-_('navigation')
-_('ui')
-_('actions')
-_('boxes')
-_('components')
-_('contentnavigation')
-
-
-def make_togglable_link(nodeid, label, cookiename):
-    """builds a HTML link that switches the visibility & remembers it"""
-    action = u"javascript: toggle_and_remember_visibility('%s', '%s')" % \
-        (nodeid, cookiename)
-    return u'<a href="%s">%s</a>' % (action, label)
-
-def css_class(someclass):
-    return someclass and 'class="%s"' % someclass or ''
-
-
-class CWPropertyPrimaryView(baseviews.PrimaryView):
-    __select__ = implements('CWProperty')
-    skip_none = False
-
-
-class SystemEPropertiesForm(FormViewMixIn, StartupView):
-    id = 'systemepropertiesform'
-    __select__ = none_rset() & match_user_groups('managers')
-
-    title = _('site configuration')
-    category = 'startupview'
-
-    def linkable(self):
-        return True
-
-    def url(self):
-        """return the url associated with this view. We can omit rql here"""
-        return self.build_url('view', vid=self.id)
-
-    def _cookie_name(self, somestr):
-        return str('%s_property_%s' % (self.config.appid, somestr))
-
-    def _group_status(self, group, default=u'hidden'):
-        """return css class name 'hidden' (collapsed), or '' (open)"""
-        cookies = self.req.get_cookie()
-        cookiename = self._cookie_name(group)
-        cookie = cookies.get(cookiename)
-        if cookie is None:
-            cookies[cookiename] = default
-            self.req.set_cookie(cookies, cookiename, maxage=None)
-            status = default
-        else:
-            status = cookie.value
-        return status
-
-    def call(self, **kwargs):
-        """The default view representing the application's index"""
-        self.req.add_js('cubicweb.preferences.js')
-        self.req.add_css('cubicweb.preferences.css')
-        vreg = self.vreg
-        values = self.defined_keys
-        groupedopts = {}
-        mainopts = {}
-        # "self.id=='systemepropertiesform'" to skip site wide properties on
-        # user's preference but not site's configuration
-        for key in vreg.user_property_keys(self.id=='systemepropertiesform'):
-            parts = key.split('.')
-            if parts[0] in vreg:
-                # appobject configuration
-                reg, oid, propid = parts
-                groupedopts.setdefault(reg, {}).setdefault(oid, []).append(key)
-            else:
-                mainopts.setdefault(parts[0], []).append(key)
-        # precompute form to consume error message
-        for group, keys in mainopts.items():
-            mainopts[group] = self.form(keys, True)
-        for group, objects in groupedopts.items():
-            for oid, keys in objects.items():
-                groupedopts[group][oid] = self.form(keys, True)
-        w = self.w
-        req = self.req
-        _ = req._
-        w(u'<h1>%s</h1>\n' % _(self.title))
-        # we don't want this in each sub-forms
-        w(u'<div id="progress">%s</div>' % self.req._('validating...'))
-        for label, group, form in sorted((_(g), g, f)
-                                         for g, f in mainopts.iteritems()):
-            status = css_class(self._group_status(group)) 
-            w(u'<h2 class="propertiesform">%s</h2>\n' %
-              (make_togglable_link('fieldset_' + group, label,
-                                   self._cookie_name(group))))
-            w(u'<div id="fieldset_%s" %s>' % (group, status))
-            w(form)
-            w(u'</div>')
-        for label, group, objects in sorted((_(g), g, o)
-                                            for g, o in groupedopts.iteritems()):
-            status = css_class(self._group_status(group))
-            w(u'<h2 class="propertiesform">%s</h2>\n' %
-              (make_togglable_link('fieldset_' + group, label,
-                                   self._cookie_name(group))))
-            w(u'<div id="fieldset_%s" %s>' % (group, status))
-            for label, oid, form in sorted((self.req.__('%s_%s' % (group, o)), o, f)
-                                           for o, f in objects.iteritems()):
-                w(u'<fieldset class="subentity">')
-                w(u'<legend class="componentTitle">%s</legend>\n' % label)
-                docmsgid = '%s_%s_description' % (group, oid)
-                doc = _(docmsgid)
-                if doc != docmsgid:
-                    w(u'<p class="description">%s</p>' % html_escape(doc))
-                w(form)
-                w(u'</fieldset>')
-            w(u'</div>')
-
-    @property
-    @cached
-    def eprops_rset(self):
-        return self.req.execute('Any P,K,V WHERE P is CWProperty, P pkey K, '
-                                'P value V, NOT P for_user U')
-
-    @property
-    def defined_keys(self):
-        values = {}
-        for i, entity in enumerate(self.eprops_rset.entities()):
-            values[entity.pkey] = i
-        return values
-
-    def entity_for_key(self, key):
-        values = self.defined_keys
-        if key in values:
-            entity = self.eprops_rset.get_entity(values[key], 0)
-        else:
-            entity = self.vreg.etype_class('CWProperty')(self.req, None, None)
-            entity.eid = self.req.varmaker.next()
-            entity['pkey'] = key
-            entity['value'] = self.vreg.property_value(key)
-        return entity
-
-    def form(self, keys, splitlabel=False):
-        buttons = [SubmitButton(),
-                   Button(stdmsgs.BUTTON_CANCEL, cwaction='cancel')]
-        form = CompositeForm(self.req, domid=None, action=self.build_url(),
-                             form_buttons=buttons, 
-                             submitmsg=self.req._('changes applied'))
-        path = self.req.relative_path()
-        if '?' in path:
-            path, params = path.split('?', 1)
-            form.form_add_hidden('__redirectparams', params)
-        form.form_add_hidden('__redirectpath', path)
-        for key in keys:            
-            self.form_row(form, key, splitlabel)
-        return form.form_render(display_progress_div=False)
-
-    def form_row(self, form, key, splitlabel):
-        entity = self.entity_for_key(key)
-        if splitlabel:
-            label = key.split('.')[-1]
-        else:
-            label = key
-        subform = EntityFieldsForm(self.req, entity=entity, set_error_url=False)
-        subform.append_field(PropertyValueField(name='value', label=label,
-                                                eidparam=True))
-        subform.vreg = self.vreg
-        subform.form_add_hidden('pkey', key, eidparam=True)
-        form.form_add_subform(subform)
-        return subform
-
-
-def is_user_prefs(cls, req, rset, row=None, col=0, **kwargs):
-    return req.user.eid == rset[row or 0][col]
-
-
-class EPropertiesForm(SystemEPropertiesForm):
-    id = 'epropertiesform'
-    __select__ = (
-        # we don't want guests to be able to come here
-        match_user_groups('users', 'managers') &
-        (none_rset() | ((one_line_rset() & is_user_prefs) &
-                        (one_line_rset() & match_user_groups('managers'))))
-        )
-    
-    title = _('preferences')
-
-    @property
-    def user(self):
-        if self.rset is None:
-            return self.req.user
-        return self.rset.get_entity(self.row or 0, self.col or 0)
-
-    @property
-    @cached
-    def eprops_rset(self):
-        return self.req.execute('Any P,K,V WHERE P is CWProperty, P pkey K, P value V,'
-                                'P for_user U, U eid %(x)s', {'x': self.user.eid})
-
-    def form_row(self, form, key, splitlabel):
-        subform = super(EPropertiesForm, self).form_row(form, key, splitlabel)
-        # if user is in the managers group and the property is being created,
-        # we have to set for_user explicitly
-        if not subform.edited_entity.has_eid() and self.user.matching_groups('managers'):
-            subform.form_add_hidden('for_user', self.user.eid, eidparam=True)
-
-
-# eproperty form objects ######################################################
-
-class PlaceHolderWidget(object):
-    
-    def render(self, form, field):
-        domid = form.context[field]['id']
-        # empty span as well else html validation fail (label is refering to
-        # this id)
-        return '<div id="div:%s"><span id="%s">%s</span></div>' % (
-            domid, domid, form.req._('select a key first'))
-
-
-class NotEditableWidget(object):
-    def __init__(self, value, msg=None):
-        self.value = value
-        self.msg = msg
-    
-    def render(self, form, field):
-        domid = form.context[field]['id']
-        value = '<span class="value" id="%s">%s</span>' % (domid, self.value)
-        if self.msg:
-            value + '<div class="helper">%s</div>' % self.msg
-        return value
-
-
-class PropertyKeyField(StringField):
-    """specific field for CWProperty.pkey to set the value widget according to
-    the selected key
-    """
-    widget = Select
-    
-    def render(self, form, renderer):
-        wdg = self.get_widget(form)
-        wdg.attrs['tabindex'] = form.req.next_tabindex()
-        wdg.attrs['onchange'] = "javascript:setPropValueWidget('%s', %s)" % (
-            form.edited_entity.eid, form.req.next_tabindex())
-        return wdg.render(form, self)
-    
-    def vocabulary(self, form):
-        entity = form.edited_entity
-        _ = form.req._
-        if entity.has_eid():
-            return [(_(entity.pkey), entity.pkey)]
-        # key beginning with 'system.' should usually not be edited by hand
-        choices = entity.vreg.user_property_keys()
-        return [(u'', u'')] + sorted(zip((_(v) for v in choices), choices))
-
-
-class PropertyValueField(StringField):
-    """specific field for CWProperty.value  which will be different according to
-    the selected key type and vocabulary information
-    """
-    widget = PlaceHolderWidget
-    
-    def render(self, form, renderer=None, tabindex=None):
-        wdg = self.get_widget(form)
-        if tabindex is not None:
-            wdg.attrs['tabindex'] = tabindex
-        return wdg.render(form, self)
-
-    def form_init(self, form):
-        entity = form.edited_entity
-        if not (entity.has_eid() or 'pkey' in entity):
-            # no key set yet, just include an empty div which will be filled
-            # on key selection
-            return
-        try:
-            pdef = form.vreg.property_info(entity.pkey)
-        except UnknownProperty, ex:
-            self.warning('%s (you should probably delete that property '
-                         'from the database)', ex)
-            msg = form.req._('you should probably delete that property')
-            self.widget = NotEditableWidget(entity.printable_value('value'),
-                                            '%s (%s)' % (msg, ex))
-        if entity.pkey.startswith('system.'):
-            msg = form.req._('value associated to this key is not editable '
-                             'manually')
-            self.widget = NotEditableWidget(entity.printable_value('value'), msg)
-        # XXX race condition when used from CWPropertyForm, should not rely on
-        # instance attributes
-        self.initial = pdef['default']
-        self.help = pdef['help']
-        vocab = pdef['vocabulary']
-        if vocab is not None:
-            if callable(vocab):
-                # list() just in case its a generator function
-                self.choices = list(vocab(form.req))
-            else:
-                self.choices = vocab
-            wdg = Select()
-        else:
-            wdg = FIELDS[pdef['type']].widget()
-            if pdef['type'] == 'Boolean':
-                self.choices = [(form.req._('yes'), '1'), (form.req._('no'), '')]
-            elif pdef['type'] in ('Float', 'Int'):
-                wdg.attrs.setdefault('size', 3)
-        self.widget = wdg
-
-uicfg.rfields.set_rtag(PropertyKeyField, 'pkey', 'subject', 'CWProperty')
-uicfg.rfields.set_rtag(PropertyValueField, 'value', 'subject', 'CWProperty')
-    
--- a/web/views/euser.py	Tue Apr 28 13:28:37 2009 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +0,0 @@
-"""Specific views for users
-
-:organization: Logilab
-:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
-:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
-"""
-__docformat__ = "restructuredtext en"
-
-from logilab.mtconverter import html_escape
-
-from cubicweb.selectors import one_line_rset, implements, match_user_groups
-from cubicweb.view import EntityView
-from cubicweb.web import uicfg, action
-from cubicweb.web.views.baseviews import PrimaryView
-
-
-uicfg.rcategories.set_rtag('secondary', 'firstname', 'subject', 'CWUser')
-uicfg.rcategories.set_rtag('secondary', 'surname', 'subject', 'CWUser')
-uicfg.rcategories.set_rtag('metadata', 'last_login_time', 'subject', 'CWUser')
-uicfg.rcategories.set_rtag('primary', 'in_group', 'subject', 'CWUser')
-uicfg.rcategories.set_rtag('generated', 'owned_by', 'object', otype='CWUser')
-uicfg.rcategories.set_rtag('generated', 'created_by', 'object', otype='CWUser')
-uicfg.rcategories.set_rtag('metadata', 'bookmarked_by', 'object', otype='CWUser')
-uicfg.rinlined.set_rtag(True, 'use_email', 'subject', 'CWUser')
-uicfg.rmode.set_rtag('create', 'in_group', 'subject', 'CWGroup')
-uicfg.rmode.set_rtag('link', 'owned_by', 'object', 'CWUser')
-uicfg.rmode.set_rtag('link', 'created_by', 'object', 'CWUser')
-uicfg.rmode.set_rtag('create', 'bookmarked_by', 'object', 'CWUser')
-    
-
-class UserPreferencesEntityAction(action.Action):
-    id = 'prefs'
-    __select__ = (one_line_rset() & implements('CWUser') &
-                  match_user_groups('owners', 'managers'))
-    
-    title = _('preferences')
-    category = 'mainactions'
-    
-    def url(self):
-        login = self.rset.get_entity(self.row or 0, self.col or 0).login
-        return self.build_url('euser/%s'%login, vid='epropertiesform')
-
-
-class CWUserPrimaryView(PrimaryView):
-    __select__ = implements('CWUser')
-    
-    skip_attrs = ('firstname', 'surname')
-    
-    def iter_relations(self, entity):
-        # don't want to display user's entities
-        for rschema, targetschemas, x in super(CWUserPrimaryView, self).iter_relations(entity):
-            if x == 'object' and rschema.type in ('owned_by', 'for_user'):
-                continue
-            yield rschema, targetschemas, x
-
-    def content_title(self, entity):
-        return entity.name()
-
-    def is_side_related(self, rschema, eschema):
-        return  rschema.type in ['interested_in', 'tags', 
-                                 'todo_by', 'bookmarked_by',
-
-                                 ]
-class FoafView(EntityView):
-    id = 'foaf'
-    __select__ = implements('CWUser')
-    
-    title = _('foaf')
-    templatable = False
-    content_type = 'text/xml'
-
-    def call(self):
-        self.w(u'''<?xml version="1.0" encoding="%s"?>
-<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-         xmlns:rdfs="http://www.w3org/2000/01/rdf-schema#"
-         xmlns:foaf="http://xmlns.com/foaf/0.1/"> '''% self.req.encoding)
-        for i in xrange(self.rset.rowcount):
-            self.cell_call(i, 0)
-        self.w(u'</rdf:RDF>\n')
-
-    def cell_call(self, row, col):
-        entity = self.complete_entity(row, col)
-        self.w(u'''<foaf:PersonalProfileDocument rdf:about="">
-                      <foaf:maker rdf:resource="%s"/>
-                      <foaf:primaryTopic rdf:resource="%s"/>
-                   </foaf:PersonalProfileDocument>''' % (entity.absolute_url(), entity.absolute_url()))
-        self.w(u'<foaf:Person rdf:ID="%s">\n' % entity.eid)
-        self.w(u'<foaf:name>%s</foaf:name>\n' % html_escape(entity.dc_long_title()))
-        if entity.surname:
-            self.w(u'<foaf:family_name>%s</foaf:family_name>\n'
-                   % html_escape(entity.surname))
-        if entity.firstname:
-            self.w(u'<foaf:givenname>%s</foaf:givenname>\n'
-                   % html_escape(entity.firstname))
-        emailaddr = entity.get_email()
-        if emailaddr:
-            self.w(u'<foaf:mbox>%s</foaf:mbox>\n' % html_escape(emailaddr))
-        self.w(u'</foaf:Person>\n')
-
-from logilab.common.deprecation import class_renamed
-EUserPrimaryView = class_renamed('EUserPrimaryView', CWUserPrimaryView)
--- a/web/views/idownloadable.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/idownloadable.py	Tue Apr 28 19:12:52 2009 +0200
@@ -43,9 +43,10 @@
     id = 'download_box'
     # no download box for images
     # XXX primary_view selector ?
-    __select__ = (one_line_rset() & implements(IDownloadable) & match_context_prop() & ~score_entity(is_image))
+    __select__ = (one_line_rset() & implements(IDownloadable) &
+                  match_context_prop() & ~score_entity(is_image))
     order = 10
-    
+
     def cell_call(self, row, col, title=None, label=None, **kwargs):
         entity = self.entity(row, col)
         download_box(self.w, entity, title, label)
@@ -86,14 +87,14 @@
     __select__ = implements(IDownloadable)
     title = None # should not be listed in possible views
 
-    
+
     def cell_call(self, row, col, title=None, **kwargs):
         entity = self.entity(row, col)
         url = html_escape(entity.download_url())
         self.w(u'<a href="%s">%s</a>' % (url, html_escape(title or entity.dc_title())))
 
 
-                                                                                
+
 class IDownloadablePrimaryView(baseviews.PrimaryView):
     __select__ = implements(IDownloadable)
     # XXX File/Image attributes but this is not specified in the IDownloadable interface
@@ -103,7 +104,7 @@
         self.w(u'<h1>%s %s</h1>'
                % (entity.dc_type().capitalize(),
                   html_escape(entity.dc_title())))
-    
+
     def render_entity_attributes(self, entity, siderelations):
         super(IDownloadablePrimaryView, self).render_entity_attributes(entity, siderelations)
         self.w(u'<div class="content">')
@@ -121,7 +122,7 @@
                 msg = self.req._("can't display data, unexpected error: %s") % ex
                 self.w('<div class="error">%s</div>' % msg)
         self.w(u'</div>')
-            
+
     def is_side_related(self, rschema, eschema):
         """display all relations as side related"""
         return True
@@ -143,16 +144,16 @@
 class ImageView(baseviews.EntityView):
     id = 'image'
     __select__ = implements(IDownloadable) & score_entity(is_image)
-    
+
     title = _('image')
-    
+
     def call(self):
         rset = self.rset
         for i in xrange(len(rset)):
             self.w(u'<div class="efile">')
             self.wview(self.id, rset, row=i, col=0)
             self.w(u'</div>')
-    
+
     def cell_call(self, row, col):
         entity = self.entity(row, col)
         #if entity.data_format.startswith('image/'):
--- a/web/views/management.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/management.py	Tue Apr 28 19:12:52 2009 +0200
@@ -48,7 +48,7 @@
             self.owned_by_edit_form(entity)
         else:
             self.owned_by_information(entity)
-        # epermissions
+        # cwpermissions
         if 'require_permission' in entity.e_schema.subject_relations():
             w('<h3>%s</h3>' % _('permissions for this entity'))
             reqpermschema = self.schema.rschema('require_permission')
@@ -116,18 +116,18 @@
             w(u'<table class="schemaInfo">')
             w(u'<tr><th>%s</th><th>%s</th></tr>' % (_("permission"),
                                                     _('granted to groups')))
-            for eperm in entity.require_permission:
+            for cwperm in entity.require_permission:
                 w(u'<tr>')
                 if dellinktempl:
-                    w(u'<td>%s%s</td>' % (dellinktempl % eperm.eid,
-                                          eperm.view('oneline')))
+                    w(u'<td>%s%s</td>' % (dellinktempl % cwperm.eid,
+                                          cwperm.view('oneline')))
                 else:
-                    w(u'<td>%s</td>' % eperm.view('oneline'))
-                w(u'<td>%s</td>' % self.view('csv', eperm.related('require_group'), 'null'))
+                    w(u'<td>%s</td>' % cwperm.view('oneline'))
+                w(u'<td>%s</td>' % self.view('csv', cwperm.related('require_group'), 'null'))
                 w(u'</tr>\n')
             w(u'</table>')
         else:
-            self.w(self.req._('no associated epermissions'))
+            self.w(self.req._('no associated permissions'))
 
     def require_permission_edit_form(self, entity):
         w = self.w
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/views/primary.py	Tue Apr 28 19:12:52 2009 +0200
@@ -0,0 +1,242 @@
+"""The default primary view
+
+:organization: Logilab
+:copyright: 2001-2009 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
+"""
+
+from warnings import warn
+
+from cubicweb import Unauthorized
+from cubicweb.view import EntityView
+
+_ = unicode
+
+PRIMARY_SKIP_RELS = set(['is', 'is_instance_of', 'identity',
+                         'owned_by', 'created_by',
+                         'in_state', 'wf_info_for', 'require_permission',
+                         'from_entity', 'to_entity',
+                         'see_also'])
+
+class PrimaryView(EntityView):
+    """the full view of an non final entity"""
+    id = 'primary'
+    title = _('primary')
+    show_attr_label = True
+    show_rel_label = True
+    skip_none = True
+    skip_attrs = ('eid', 'creation_date', 'modification_date')
+    skip_rels = ()
+    main_related_section = True
+
+    def html_headers(self):
+        """return a list of html headers (eg something to be inserted between
+        <head> and </head> of the returned page
+
+        by default primary views are indexed
+        """
+        return []
+
+    def cell_call(self, row, col):
+        self.row = row
+        # XXX move render_entity implementation here
+        self.render_entity(self.complete_entity(row, col))
+
+    def render_entity(self, entity):
+        """return html to display the given entity"""
+        self.render_entity_title(entity)
+        self.render_entity_metadata(entity)
+        # entity's attributes and relations, excluding meta data
+        # if the entity isn't meta itself
+        boxes = self._preinit_side_related(entity)
+        if boxes:
+            self.w(u'<table width="100%"><tr><td width="75%">')
+        self.w(u'<div>')
+        self.w(u'<div class="mainInfo">')
+        try:
+            self.render_entity_attributes(entity)
+        except TypeError: # XXX bw compat
+            warn('siderelations argument of render_entity_attributes is '
+                 'deprecated')
+            self.render_entity_attributes(entity, [])
+        self.w(u'</div>')
+        self.content_navigation_components('navcontenttop')
+        if self.main_related_section:
+            try:
+                self.render_entity_relations(entity)
+            except TypeError: # XXX bw compat
+                warn('siderelations argument of render_entity_relations is '
+                     'deprecated')
+                self.render_entity_relations(entity, [])
+        self.w(u'</div>')
+        if boxes:
+            self.w(u'</td><td>')
+            # side boxes
+            self.w(u'<div class="primaryRight">')
+            try:
+                self.render_side_related(entity)
+            except TypeError: # XXX bw compat
+                warn('siderelations argument of render_entity_relations is '
+                     'deprecated')
+                self.render_entity_relations(entity, [])
+            self.w(u'</div>')
+            self.w(u'</td></tr></table>')
+        self.content_navigation_components('navcontentbottom')
+
+
+    def content_navigation_components(self, context):
+        self.w(u'<div class="%s">' % context)
+        for comp in self.vreg.possible_vobjects('contentnavigation',
+                                                self.req, self.rset, row=self.row,
+                                                view=self, context=context):
+            try:
+                comp.dispatch(w=self.w, row=self.row, view=self)
+            except NotImplementedError:
+                warn('component %s doesnt implement cell_call, please update'
+                     % comp.__class__, DeprecationWarning)
+                comp.dispatch(w=self.w, view=self)
+        self.w(u'</div>')
+
+    def iter_attributes(self, entity):
+        for rschema, targetschema in entity.e_schema.attribute_definitions():
+            if rschema.type in self.skip_attrs:
+                continue
+            yield rschema, targetschema
+
+    def iter_relations(self, entity):
+        skip = set(self.skip_rels)
+        skip.update(PRIMARY_SKIP_RELS)
+        for rschema, targetschemas, x in entity.e_schema.relation_definitions():
+            if rschema.type in skip:
+                continue
+            yield rschema, targetschemas, x
+
+    def render_entity_title(self, entity):
+        title = self.content_title(entity) # deprecate content_title?
+        if title:
+            self.w(u'<h1><span class="etype">%s</span> %s</h1>'
+                   % (entity.dc_type().capitalize(), title))
+
+    def content_title(self, entity):
+        """default implementation return an empty string"""
+        return u''
+
+    def render_entity_metadata(self, entity):
+        entity.view('metadata', w=self.w)
+        summary = self.summary(entity) # deprecate summary?
+        if summary:
+            self.w(u'<div class="summary">%s</div>' % summary)
+
+    def summary(self, entity):
+        """default implementation return an empty string"""
+        return u''
+
+    def render_entity_attributes(self, entity, siderelations=None):
+        for rschema, targetschema in self.iter_attributes(entity):
+            attr = rschema.type
+            if targetschema.type in ('Password', 'Bytes'):
+                continue
+            try:
+                wdg = entity.get_widget(attr)
+            except Exception, ex:
+                value = entity.printable_value(attr, entity[attr], targetschema.type)
+            else:
+                value = wdg.render(entity)
+            if self.skip_none and (value is None or value == ''):
+                continue
+            if rschema.meta:
+                continue
+            self._render_related_entities(entity, rschema, value)
+
+    def _preinit_side_related(self, entity):
+        self._sideboxes = []
+        if hasattr(self, 'get_side_boxes_defs'):
+            self._sideboxes = [(label, rset, 'sidebox') for label, rset in self.get_side_boxes_defs(entity)
+                               if rset]
+        else:
+            eschema = entity.e_schema
+            maxrelated = self.req.property_value('navigation.related-limit')
+            for rschema, targetschemas, role in self.iter_relations(entity):
+                if self.is_side_related(rschema, eschema):
+                    try:
+                        related = entity.related(rschema.type, role, limit=maxrelated+1)
+                    except Unauthorized:
+                        continue
+                    if not related:
+                        continue
+                    label = display_name(self.req, rschema.type, role)
+                    self._sideboxes.append((label, related, 'autolimited'))
+        self._contextboxes = list(self.vreg.possible_vobjects('boxes', self.req, self.rset,
+                                                                  row=self.row, view=self,
+                                                                  context='incontext'))
+        return self._sideboxes or self._contextboxes
+
+    def render_entity_relations(self, entity, siderelations=None):
+        eschema = entity.e_schema
+        for rschema, targetschemas, x in self.iter_relations(entity):
+            if not self.is_side_related(rschema, eschema):
+                try:
+                    related = entity.related(rschema.type, x, limit=maxrelated+1)
+                except Unauthorized:
+                    continue
+                self._render_related_entities(entity, rschema, related, x)
+
+
+    def render_side_related(self, entity, siderelations=None):
+        """display side related relations:
+        non-meta in a first step, meta in a second step
+        """
+        if self._sideboxes:
+            for label, rset, vid in self._sideboxes:
+                self.w(u'<div class="sideRelated">')
+                self.wview(vid, rset, title=label)
+                self.w(u'</div>')
+        if self._contextboxes:
+            for box in self._contextboxes:
+                try:
+                    box.dispatch(w=self.w, row=self.row)
+                except NotImplementedError:
+                    # much probably a context insensitive box, which only implements
+                    # .call() and not cell_call()
+                    box.dispatch(w=self.w)
+
+    def is_side_related(self, rschema, eschema):
+        return rschema.meta and \
+               not rschema.schema_relation() == eschema.schema_entity()
+
+    def _render_related_entities(self, entity, rschema, related,
+                                 role='subject'):
+        if rschema.is_final():
+            value = related
+            show_label = self.show_attr_label
+        else:
+            if not related:
+                return
+            value = self.view('autolimited', related)
+        label = display_name(self.req, rschema.type, role)
+        self.field(label, value, show_label=show_label, tr=False)
+
+
+class RelatedView(EntityView):
+    id = 'autolimited'
+    def call(self):
+        # if not too many entities, show them all in a list
+        maxrelated = self.req.property_value('navigation.related-limit')
+        if self.rset.rowcount <= maxrelated:
+            if self.rset.rowcount == 1:
+                self.wview('incontext', self.rset, row=0)
+            elif 1 < self.rset.rowcount <= 5:
+                self.wview('csv', self.rset)
+            else:
+                self.w(u'<div>')
+                self.wview('simplelist', self.rset)
+                self.w(u'</div>')
+        # else show links to display related entities
+        else:
+            rql = self.rset.printable_rql()
+            self.rset.limit(maxself.rset)
+            self.w(u'<div>')
+            self.wview('simplelist', self.rset)
+            self.w(u'[<a href="%s">%s</a>]' % (self.build_url(rql=rql),
+                                               self.req._('see them all')))
+            self.w(u'</div>')
--- a/web/views/schema.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/schema.py	Tue Apr 28 19:12:52 2009 +0200
@@ -15,49 +15,46 @@
 from cubicweb.schemaviewer import SchemaViewer
 from cubicweb.view import EntityView, StartupView
 from cubicweb.common.uilib import ureport_as_html
-from cubicweb.web.action import Action
-from cubicweb.web.views import baseviews
-from cubicweb.web.views import TmpFileViewMixin
-from cubicweb.web.views.editforms import AutomaticEntityForm
-from cubicweb.web.views.boxes import EditBox
+from cubicweb.web import uicfg, action
+from cubicweb.web.views import TmpFileViewMixin, baseviews
 
 
-AutomaticEntityForm.rcategories.set_rtag('primary', 'require_group', 'subject', 'CWPermission')
-AutomaticEntityForm.rcategories.set_rtag('generated', 'final', 'subject', 'EEtype')
-AutomaticEntityForm.rcategories.set_rtag('generated', 'final', 'subject', 'ERtype')
-AutomaticEntityForm.rinlined.set_rtag(True, 'relation_type', 'subject', 'CWRelation')
-AutomaticEntityForm.rinlined.set_rtag(True, 'from_entity', 'subject', 'CWRelation')
-AutomaticEntityForm.rinlined.set_rtag(True, 'to_entity', 'subject', 'CWRelation')
-AutomaticEntityForm.rwidgets.set_rtag('StringWidget', 'expression', 'subject', 'RQLExpression')
+uicfg.rcategories.set_rtag('primary', 'require_group', 'subject', 'CWPermission')
+uicfg.rcategories.set_rtag('generated', 'final', 'subject', 'EEtype')
+uicfg.rcategories.set_rtag('generated', 'final', 'subject', 'ERtype')
+uicfg.rinlined.set_rtag(True, 'relation_type', 'subject', 'CWRelation')
+uicfg.rinlined.set_rtag(True, 'from_entity', 'subject', 'CWRelation')
+uicfg.rinlined.set_rtag(True, 'to_entity', 'subject', 'CWRelation')
+uicfg.rwidgets.set_rtag('StringWidget', 'expression', 'subject', 'RQLExpression')
 
-EditBox.rmode.set_rtag('create', 'state_of', 'object', 'CWEType')
-EditBox.rmode.set_rtag('create', 'transition_of', 'object', 'CWEType')
-EditBox.rmode.set_rtag('create', 'relation_type', 'object', 'CWRType')
-EditBox.rmode.set_rtag('link', 'from_entity', 'object', 'CWEType')
-EditBox.rmode.set_rtag('link', 'to_entity', 'object', 'CWEType')
+uicfg.rmode.set_rtag('create', 'state_of', 'object', otype='CWEType')
+uicfg.rmode.set_rtag('create', 'transition_of', 'object', otype='CWEType')
+uicfg.rmode.set_rtag('create', 'relation_type', 'object', otype='CWRType')
+uicfg.rmode.set_rtag('link', 'from_entity', 'object', otype='CWEType')
+uicfg.rmode.set_rtag('link', 'to_entity', 'object', otype='CWEType')
 
 
-class ViewSchemaAction(Action):
+class ViewSchemaAction(action.Action):
     id = 'schema'
     __select__ = yes()
-    
+
     title = _("site schema")
     category = 'siteactions'
     order = 30
-    
+
     def url(self):
         return self.build_url(self.id)
-    
-        
+
+
 # schema entity types views ###################################################
 
 class _SchemaEntityPrimaryView(baseviews.PrimaryView):
     show_attr_label = False
-    cache_max_age = 60*60*2 # stay in http cache for 2 hours by default 
-    
+    cache_max_age = 60*60*2 # stay in http cache for 2 hours by default
+
     def content_title(self, entity):
         return html_escape(entity.dc_long_title())
-    
+
 class CWETypePrimaryView(_SchemaEntityPrimaryView):
     __select__ = implements('CWEType')
     skip_attrs = _SchemaEntityPrimaryView.skip_attrs + ('name', 'meta', 'final')
@@ -73,7 +70,7 @@
 
 class CWETypeOneLineView(baseviews.OneLineView):
     __select__ = implements('CWEType')
-    
+
     def cell_call(self, row, col, **kwargs):
         entity = self.entity(row, col)
         final = entity.final
@@ -92,7 +89,7 @@
     main_related_section = False
     skip_rels = ('is', 'is_instance_of', 'identity', 'created_by', 'owned_by',
                  'has_text',)
-    
+
     def render_entity_attributes(self, entity, siderelations):
         super(CWETypeSchemaView, self).render_entity_attributes(entity, siderelations)
         eschema = self.vreg.schema.eschema(entity.name)
@@ -120,7 +117,7 @@
             self.w(u'<img src="%s" alt="%s"/>' % (
                 html_escape(entity.absolute_url(vid='eschemagraph')),
                 html_escape(self.req._('graphical schema for %s') % entity.name)))
-        
+
 
 # schema images ###############################################################
 
@@ -143,11 +140,11 @@
         self.nextcolor = cycle( ('#aa0000', '#00aa00', '#0000aa',
                                  '#000000', '#888888') ).next
         self.req = req
-        
+
     def display_attr(self, rschema):
         return not rschema.meta and (rschema.has_local_role('read')
                                      or rschema.has_perm(self.req, 'read'))
-    
+
     # XXX remove this method once yams > 0.20 is out
     def node_properties(self, eschema):
         """return default DOT drawing options for an entity schema"""
@@ -168,7 +165,7 @@
         # + 1 line going to the closest edge spline point)
         kwargs['decorate'] = 'false'
         return kwargs
-    
+
 
 class RestrictedSchemaVisitorMiIn:
     def __init__(self, req, *args, **kwargs):
@@ -177,12 +174,12 @@
         self.__parent = self.__class__.__bases__[1]
         self.__parent.__init__(self, *args, **kwargs)
         self.req = req
-        
+
     def nodes(self):
         for etype, eschema in self.__parent.nodes(self):
             if eschema.has_local_role('read') or eschema.has_perm(self.req, 'read'):
                 yield eschema.type, eschema
-            
+
     def edges(self):
         for setype, oetype, rschema in self.__parent.edges(self):
             if rschema.has_local_role('read') or rschema.has_perm(self.req, 'read'):
@@ -215,7 +212,7 @@
     content_type = 'image/png'
     __select__ = implements('CWEType')
     skip_rels = ('owned_by', 'created_by', 'identity', 'is', 'is_instance_of')
-    
+
     def _generate(self, tmpfile):
         """display schema information for an entity"""
         entity = self.entity(self.row, self.col)
@@ -226,7 +223,7 @@
 
 class CWRTypeSchemaImageView(CWETypeSchemaImageView):
     __select__ = implements('CWRType')
-    
+
     def _generate(self, tmpfile):
         """display schema information for an entity"""
         entity = self.entity(self.row, self.col)
--- a/web/views/startup.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/startup.py	Tue Apr 28 19:12:52 2009 +0200
@@ -19,12 +19,12 @@
 
 class ManageView(StartupView):
     id = 'manage'
-    title = _('manage')    
+    title = _('manage')
     http_cache_manager = EtagHTTPCacheManager
 
     def display_folders(self):
         return False
-    
+
     def call(self, **kwargs):
         """The default view representing the application's management"""
         self.req.add_css('cubicweb.manageview.css')
@@ -35,7 +35,7 @@
             self.w(u'<table><tr>\n')
             self.w(u'<td style="width:40%">')
             self._main_index()
-            self.w(u'</td><td style="width:60%">')            
+            self.w(u'</td><td style="width:60%">')
             self.folders()
             self.w(u'</td>')
             self.w(u'</tr></table>\n')
@@ -63,22 +63,22 @@
                 href = req.build_url('view', vid='creation', etype='Card', wikiid='index')
                 label = self.req._('create an index page')
             self.w(u'<br/><a href="%s">%s</a>\n' % (html_escape(href), label))
-        
+
     def folders(self):
         self.w(u'<h4>%s</h4>\n' % self.req._('Browse by category'))
         self.vreg.select_view('tree', self.req, None).dispatch(w=self.w)
-        
+
     def startup_views(self):
         self.w(u'<h4>%s</h4>\n' % self.req._('Startup views'))
         self.startupviews_table()
-        
+
     def startupviews_table(self):
         for v in self.vreg.possible_views(self.req, None):
             if v.category != 'startupview' or v.id in ('index', 'tree', 'manage'):
                 continue
             self.w('<p><a href="%s">%s</a></p>' % (
                 html_escape(v.url()), html_escape(self.req._(v.title).capitalize())))
-        
+
     def entities(self):
         schema = self.schema
         self.w(u'<h4>%s</h4>\n' % self.req._('The repository holds the following entities'))
@@ -88,7 +88,7 @@
             self.w(u'<tr><th colspan="4">%s</th></tr>\n' % self.req._('application entities'))
         self.entity_types_table(eschema for eschema in schema.entities()
                                 if not eschema.meta and not eschema.is_subobject(strict=True))
-        if manager: 
+        if manager:
             self.w(u'<tr><th colspan="4">%s</th></tr>\n' % self.req._('system entities'))
             self.entity_types_table(eschema for eschema in schema.entities()
                                     if eschema.meta and not eschema.schema_entity())
@@ -97,7 +97,7 @@
                 self.entity_types_table(schema.eschema(etype)
                                         for etype in schema.schema_entity_types())
         self.w(u'</table>')
-        
+
     def entity_types_table(self, eschemas):
         newline = 0
         infos = sorted(self.entity_types(eschemas),
@@ -111,8 +111,8 @@
             self.w(u'<td class="addcol">%s</td><td>%s</td>\n' % (addlink,  etypelink))
             self.w(u'<td class="addcol">%s</td><td>%s</td>\n' % (addlink2, etypelink2))
             self.w(u'</tr>\n')
-        
-        
+
+
     def entity_types(self, eschemas):
         """return a list of formatted links to get a list of entities of
         a each entity's types
@@ -133,7 +133,7 @@
             etypelink = u'&nbsp;<a href="%s">%s</a> (%d)' % (
                 html_escape(url), label, nb)
             yield (label, etypelink, self.add_entity_link(eschema, req))
-    
+
     def add_entity_link(self, eschema, req):
         """creates a [+] link for adding an entity if user has permission to do so"""
         if not eschema.has_perm(req, 'add'):
@@ -142,14 +142,14 @@
             html_escape(self.create_url(eschema.type)),
             self.req.__('add a %s' % eschema))
 
-    
+
 class IndexView(ManageView):
     id = 'index'
     title = _('index')
-    
+
     def display_folders(self):
         return 'Folder' in self.schema and self.req.execute('Any COUNT(X) WHERE X is Folder')[0][0]
-    
+
 
 
 class SchemaView(StartupView):
--- a/web/views/tabs.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/tabs.py	Tue Apr 28 19:12:52 2009 +0200
@@ -38,7 +38,7 @@
             'lazyview wants at least : rql, or an eid, or an rset -- or call it with static=True'
         w = w or self.w
         self.req.add_js('cubicweb.lazy.js')
-        urlparams = {'vid' : vid, 'mode' : 'html'}
+        urlparams = {'vid' : vid, 'fname' : 'view'}
         if rql:
             urlparams['rql'] = rql
         elif eid:
--- a/web/views/workflow.py	Tue Apr 28 13:28:37 2009 +0200
+++ b/web/views/workflow.py	Tue Apr 28 19:12:52 2009 +0200
@@ -23,10 +23,11 @@
 from cubicweb.web.views import TmpFileViewMixin
 from cubicweb.web.views.boxes import EditBox
 
+_ = unicode
 
 EditBox.rmode.set_rtag('create', 'destination_state', 'subject', 'Transition')
-EditBox.rmode.set_rtag('create', 'allowed_transition', 'object', 'Transition')
-EditBox.rmode.set_rtag('create', 'destination_state', 'object', 'State')
+EditBox.rmode.set_rtag('create', 'allowed_transition', 'object', otype='Transition')
+EditBox.rmode.set_rtag('create', 'destination_state', 'object', otype='State')
 EditBox.rmode.set_rtag('create', 'allowed_transition', 'subject', 'State')
 
 
@@ -34,15 +35,15 @@
 
 class ChangeStateForm(form.EntityFieldsForm):
     id = 'changestate'
-    
+
     __method = StringField(name='__method', initial='set_state',
                            widget=HiddenInput)
-    state = StringField(widget=HiddenInput, eidparam=True)
-    trcomment = RichTextField(eidparam=True)
+    state = StringField(eidparam=True, widget=HiddenInput)
+    trcomment = RichTextField(label=_('comment:'), eidparam=True)
     form_buttons = [SubmitButton(stdmsgs.YES),
                      Button(stdmsgs.NO, cwaction='cancel')]
 
-        
+
 class ChangeStateFormView(FormViewMixIn, view.EntityView):
     id = 'statuschange'
     title = _('status change')
@@ -91,7 +92,7 @@
             rql += ', WF owned_by U?'
             displaycols = range(5)
             headers = (_('from_state'), _('to_state'), _('comment'), _('date'),
-                       _('CWUser'))            
+                       _('CWUser'))
         else:
             sel += ',C'
             displaycols = range(4)
@@ -111,7 +112,7 @@
 class CellView(view.EntityView):
     id = 'cell'
     __select__ = implements('TrInfo')
-    
+
     def cell_call(self, row, col, cellvid=None):
         self.w(self.entity(row, col).printable_value('comment'))
 
@@ -120,30 +121,30 @@
     """convenience trick, State's incontext view should not be clickable"""
     id = 'incontext'
     __select__ = implements('State')
-    
+
     def cell_call(self, row, col):
         self.w(html_escape(self.view('textincontext', self.rset,
                                      row=row, col=col)))
 
 
 # workflow images #############################################################
-        
+
 class ViewWorkflowAction(action.Action):
     id = 'workflow'
     __select__ = implements('CWEType') & has_related_entities('state_of', 'object')
-    
+
     category = 'mainactions'
     title = _('view workflow')
     def url(self):
         entity = self.rset.get_entity(self.row or 0, self.col or 0)
         return entity.absolute_url(vid='workflow')
 
-        
+
 class CWETypeWorkflowView(view.EntityView):
     id = 'workflow'
     __select__ = implements('CWEType')
-    cache_max_age = 60*60*2 # stay in http cache for 2 hours by default 
-    
+    cache_max_age = 60*60*2 # stay in http cache for 2 hours by default
+
     def cell_call(self, row, col, **kwargs):
         entity = self.entity(row, col)
         self.w(u'<h1>%s</h1>' % (self.req._('workflow for %s')
@@ -156,10 +157,10 @@
 class WorkflowDotPropsHandler(object):
     def __init__(self, req):
         self._ = req._
-        
+
     def node_properties(self, stateortransition):
         """return default DOT drawing options for a state or transition"""
-        props = {'label': stateortransition.name, 
+        props = {'label': stateortransition.name,
                  'fontname': 'Courier'}
         if hasattr(stateortransition, 'state_of'):
             props['shape'] = 'box'
@@ -179,7 +180,7 @@
             if descr:
                 props['label'] += escape('\n'.join(descr))
         return props
-    
+
     def edge_properties(self, transition, fromstate, tostate):
         return {'label': '', 'dir': 'forward',
                 'color': 'black', 'style': 'filled'}
@@ -193,11 +194,11 @@
         for state in self.entity.reverse_state_of:
             state.complete()
             yield state.eid, state
-            
+
         for transition in self.entity.reverse_transition_of:
             transition.complete()
             yield transition.eid, transition
-            
+
     def edges(self):
         for transition in self.entity.reverse_transition_of:
             for incomingstate in transition.reverse_allowed_transition:
@@ -209,7 +210,7 @@
     id = 'ewfgraph'
     content_type = 'image/png'
     __select__ = implements('CWEType')
-    
+
     def _generate(self, tmpfile):
         """display schema information for an entity"""
         entity = self.entity(self.row, self.col)